apostrophe 3.63.3 → 4.1.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 (184) hide show
  1. package/.eslintrc +13 -4
  2. package/CHANGELOG.md +37 -5
  3. package/defaults.js +2 -1
  4. package/modules/@apostrophecms/admin-bar/ui/apos/apps/AposAdminBar.js +7 -17
  5. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposAdminBar.vue +14 -16
  6. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposAdminBarLocale.vue +1 -1
  7. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposAdminBarMenu.vue +22 -15
  8. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposAdminBarUser.vue +2 -2
  9. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposContextBar.vue +13 -8
  10. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposContextModeAndSettings.vue +18 -10
  11. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposContextTitle.vue +4 -4
  12. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposContextUndoRedo.vue +14 -8
  13. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposSavingIndicator.vue +2 -1
  14. package/modules/@apostrophecms/area/ui/apos/apps/AposAreas.js +36 -54
  15. package/modules/@apostrophecms/area/ui/apos/components/AposAreaContextualMenu.vue +20 -25
  16. package/modules/@apostrophecms/area/ui/apos/components/AposAreaEditor.vue +5 -12
  17. package/modules/@apostrophecms/area/ui/apos/components/AposAreaExpandedMenu.vue +11 -3
  18. package/modules/@apostrophecms/area/ui/apos/components/AposAreaMenu.vue +6 -6
  19. package/modules/@apostrophecms/area/ui/apos/components/AposAreaMenuItem.vue +3 -2
  20. package/modules/@apostrophecms/area/ui/apos/components/AposAreaWidget.vue +31 -44
  21. package/modules/@apostrophecms/area/ui/apos/components/AposWidgetControls.vue +16 -16
  22. package/modules/@apostrophecms/asset/index.js +25 -12
  23. package/modules/@apostrophecms/asset/lib/webpack/apos/webpack.config.js +3 -3
  24. package/modules/@apostrophecms/asset/lib/webpack/apos/webpack.vue.js +7 -1
  25. package/modules/@apostrophecms/attachment/index.js +2 -1
  26. package/modules/@apostrophecms/attachment/public/img/missing-icon.svg +14 -0
  27. package/modules/@apostrophecms/busy/ui/apos/apps/AposBusy.js +8 -7
  28. package/modules/@apostrophecms/busy/ui/apos/components/TheAposBusy.vue +1 -1
  29. package/modules/@apostrophecms/command-menu/ui/apos/apps/AposCommandMenu.js +11 -29
  30. package/modules/@apostrophecms/command-menu/ui/apos/components/AposCommandMenuKey.vue +1 -1
  31. package/modules/@apostrophecms/command-menu/ui/apos/components/AposCommandMenuShortcut.vue +6 -6
  32. package/modules/@apostrophecms/command-menu/ui/apos/components/TheAposCommandMenu.vue +10 -7
  33. package/modules/@apostrophecms/doc-type/index.js +34 -13
  34. package/modules/@apostrophecms/doc-type/ui/apos/components/AposDocContextMenu.vue +3 -3
  35. package/modules/@apostrophecms/doc-type/ui/apos/components/AposDocEditor.vue +20 -15
  36. package/modules/@apostrophecms/doc-type/ui/apos/logic/AposDocContextMenu.js +1 -1
  37. package/modules/@apostrophecms/i18n/i18n/en.json +13 -0
  38. package/modules/@apostrophecms/i18n/ui/apos/components/AposI18nLocalize.vue +209 -33
  39. package/modules/@apostrophecms/i18n/ui/apos/components/AposI18nLocalizeErrors.vue +3 -3
  40. package/modules/@apostrophecms/image/ui/apos/components/AposImageCropper.vue +5 -5
  41. package/modules/@apostrophecms/image/ui/apos/components/AposImageRelationshipEditor.vue +6 -6
  42. package/modules/@apostrophecms/image/ui/apos/components/AposMediaManager.vue +23 -16
  43. package/modules/@apostrophecms/image/ui/apos/components/AposMediaManagerDisplay.vue +11 -11
  44. package/modules/@apostrophecms/image/ui/apos/components/AposMediaManagerEditor.vue +28 -21
  45. package/modules/@apostrophecms/image/ui/apos/components/AposMediaManagerSelections.vue +4 -3
  46. package/modules/@apostrophecms/image/ui/apos/components/AposMediaUploader.vue +5 -4
  47. package/modules/@apostrophecms/login/index.js +18 -1
  48. package/modules/@apostrophecms/login/ui/apos/apps/AposLogin.js +6 -7
  49. package/modules/@apostrophecms/login/ui/apos/components/AposForgotPasswordForm.vue +3 -3
  50. package/modules/@apostrophecms/login/ui/apos/components/AposLoginForm.vue +10 -10
  51. package/modules/@apostrophecms/login/ui/apos/components/AposResetPasswordForm.vue +3 -3
  52. package/modules/@apostrophecms/login/ui/apos/components/TheAposLogin.vue +2 -2
  53. package/modules/@apostrophecms/login/ui/apos/logic/AposLoginForm.js +1 -16
  54. package/modules/@apostrophecms/modal/ui/apos/apps/AposModals.js +60 -87
  55. package/modules/@apostrophecms/modal/ui/apos/components/AposDocsManagerToolbar.vue +15 -11
  56. package/modules/@apostrophecms/modal/ui/apos/components/AposModal.vue +17 -11
  57. package/modules/@apostrophecms/modal/ui/apos/components/AposModalBreadcrumbs.vue +7 -4
  58. package/modules/@apostrophecms/modal/ui/apos/components/AposModalConfirm.vue +9 -9
  59. package/modules/@apostrophecms/modal/ui/apos/components/AposModalLip.vue +2 -2
  60. package/modules/@apostrophecms/modal/ui/apos/components/AposModalShareDraft.vue +8 -8
  61. package/modules/@apostrophecms/modal/ui/apos/components/AposModalTabs.vue +4 -3
  62. package/modules/@apostrophecms/modal/ui/apos/components/AposModalToolbar.vue +7 -7
  63. package/modules/@apostrophecms/modal/ui/apos/components/TheAposModals.vue +22 -4
  64. package/modules/@apostrophecms/modal/ui/apos/composables/AposFocus.js +95 -0
  65. package/modules/@apostrophecms/modal/ui/apos/mixins/AposDocsManagerMixin.js +2 -3
  66. package/modules/@apostrophecms/modal/ui/apos/mixins/AposEditorMixin.js +6 -0
  67. package/modules/@apostrophecms/notification/index.js +4 -4
  68. package/modules/@apostrophecms/notification/ui/apos/apps/AposNotification.js +6 -9
  69. package/modules/@apostrophecms/notification/ui/apos/components/AposNotification.vue +12 -8
  70. package/modules/@apostrophecms/notification/ui/apos/components/TheAposNotifications.vue +4 -2
  71. package/modules/@apostrophecms/oembed-field/ui/apos/components/AposInputOembed.vue +12 -10
  72. package/modules/@apostrophecms/page/index.js +1 -0
  73. package/modules/@apostrophecms/page/ui/apos/components/AposPagesManager.vue +15 -11
  74. package/modules/@apostrophecms/page/ui/apos/logic/AposPagesManager.js +1 -1
  75. package/modules/@apostrophecms/permission/ui/apos/components/AposInputRole.vue +3 -3
  76. package/modules/@apostrophecms/piece-type/ui/apos/components/AposDocsManager.vue +25 -17
  77. package/modules/@apostrophecms/piece-type/ui/apos/components/AposDocsManagerDisplay.vue +24 -20
  78. package/modules/@apostrophecms/piece-type/ui/apos/components/AposDocsManagerSelectBox.vue +9 -5
  79. package/modules/@apostrophecms/piece-type/ui/apos/components/AposRelationshipEditor.vue +15 -11
  80. package/modules/@apostrophecms/rich-text-widget/index.js +1 -0
  81. package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposImageControlDialog.vue +7 -6
  82. package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposRichTextWidgetEditor.vue +31 -30
  83. package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposTiptapAnchor.vue +12 -10
  84. package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposTiptapButton.vue +1 -1
  85. package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposTiptapImage.vue +1 -1
  86. package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposTiptapLink.vue +9 -8
  87. package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposTiptapStyles.vue +3 -3
  88. package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposTiptapTable.vue +3 -3
  89. package/modules/@apostrophecms/schema/index.js +69 -8
  90. package/modules/@apostrophecms/schema/lib/addFieldTypes.js +1 -1
  91. package/modules/@apostrophecms/schema/ui/apos/components/AposArrayEditor.vue +10 -8
  92. package/modules/@apostrophecms/schema/ui/apos/components/AposInputArea.vue +5 -3
  93. package/modules/@apostrophecms/schema/ui/apos/components/AposInputArray.vue +81 -277
  94. package/modules/@apostrophecms/schema/ui/apos/components/AposInputAttachment.vue +4 -2
  95. package/modules/@apostrophecms/schema/ui/apos/components/AposInputBoolean.vue +24 -14
  96. package/modules/@apostrophecms/schema/ui/apos/components/AposInputCheckboxes.vue +7 -6
  97. package/modules/@apostrophecms/schema/ui/apos/components/AposInputColor.vue +10 -7
  98. package/modules/@apostrophecms/schema/ui/apos/components/AposInputObject.vue +3 -3
  99. package/modules/@apostrophecms/schema/ui/apos/components/AposInputPassword.vue +6 -4
  100. package/modules/@apostrophecms/schema/ui/apos/components/AposInputRadio.vue +5 -4
  101. package/modules/@apostrophecms/schema/ui/apos/components/AposInputRange.vue +9 -6
  102. package/modules/@apostrophecms/schema/ui/apos/components/AposInputRelationship.vue +15 -12
  103. package/modules/@apostrophecms/schema/ui/apos/components/AposInputSelect.vue +1 -1
  104. package/modules/@apostrophecms/schema/ui/apos/components/AposInputSlug.vue +16 -12
  105. package/modules/@apostrophecms/schema/ui/apos/components/AposInputString.vue +19 -11
  106. package/modules/@apostrophecms/schema/ui/apos/components/AposInputWrapper.vue +15 -12
  107. package/modules/@apostrophecms/schema/ui/apos/components/AposSchema.vue +75 -22
  108. package/modules/@apostrophecms/schema/ui/apos/components/AposSearchList.vue +1 -1
  109. package/modules/@apostrophecms/schema/ui/apos/components/AposSubform.vue +2 -2
  110. package/modules/@apostrophecms/schema/ui/apos/logic/AposArrayEditor.js +0 -4
  111. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputArea.js +3 -3
  112. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputArray.js +15 -4
  113. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputAttachment.js +3 -3
  114. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputCheckboxes.js +7 -7
  115. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputColor.js +5 -8
  116. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputDateAndTime.js +1 -1
  117. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputObject.js +1 -1
  118. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputRadio.js +1 -1
  119. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputRelationship.js +12 -9
  120. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputSelect.js +3 -3
  121. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputString.js +7 -9
  122. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputWrapper.js +4 -4
  123. package/modules/@apostrophecms/schema/ui/apos/logic/AposSchema.js +42 -13
  124. package/modules/@apostrophecms/schema/ui/apos/logic/AposSubform.js +1 -1
  125. package/modules/@apostrophecms/schema/ui/apos/mixins/AposInputMixin.js +9 -9
  126. package/modules/@apostrophecms/schema/ui/apos/scss/AposInputArray.scss +205 -0
  127. package/modules/@apostrophecms/settings/ui/apos/components/AposSettingsManager.vue +5 -5
  128. package/modules/@apostrophecms/settings/ui/apos/logic/AposSettingsManager.js +4 -4
  129. package/modules/@apostrophecms/submitted-draft/ui/apos/components/AposSubmittedDraftIcon.vue +5 -4
  130. package/modules/@apostrophecms/task/index.js +2 -0
  131. package/modules/@apostrophecms/translation/index.js +233 -0
  132. package/modules/@apostrophecms/translation/ui/apos/components/AposTranslationIndicator.vue +84 -0
  133. package/modules/@apostrophecms/ui/ui/apos/components/AposAvatar.vue +2 -1
  134. package/modules/@apostrophecms/ui/ui/apos/components/AposButton.vue +4 -4
  135. package/modules/@apostrophecms/ui/ui/apos/components/AposButtonGroup.vue +6 -6
  136. package/modules/@apostrophecms/ui/ui/apos/components/AposButtonSplit.vue +120 -113
  137. package/modules/@apostrophecms/ui/ui/apos/components/AposCellButton.vue +2 -1
  138. package/modules/@apostrophecms/ui/ui/apos/components/AposCellLabels.vue +49 -5
  139. package/modules/@apostrophecms/ui/ui/apos/components/AposCheckbox.vue +19 -19
  140. package/modules/@apostrophecms/ui/ui/apos/components/AposCloudUploadIcon.vue +10 -5
  141. package/modules/@apostrophecms/ui/ui/apos/components/AposCombo.vue +15 -15
  142. package/modules/@apostrophecms/ui/ui/apos/components/AposContextMenu.vue +214 -191
  143. package/modules/@apostrophecms/ui/ui/apos/components/AposContextMenuDialog.vue +77 -65
  144. package/modules/@apostrophecms/ui/ui/apos/components/AposContextMenuItem.vue +1 -1
  145. package/modules/@apostrophecms/ui/ui/apos/components/AposContextMenuTip.vue +28 -50
  146. package/modules/@apostrophecms/ui/ui/apos/components/AposEmptyState.vue +3 -3
  147. package/modules/@apostrophecms/ui/ui/apos/components/AposFile.vue +5 -5
  148. package/modules/@apostrophecms/ui/ui/apos/components/AposFilterMenu.vue +4 -4
  149. package/modules/@apostrophecms/ui/ui/apos/components/AposIndicator.vue +1 -1
  150. package/modules/@apostrophecms/ui/ui/apos/components/AposLabel.vue +1 -1
  151. package/modules/@apostrophecms/ui/ui/apos/components/AposMinMaxCount.vue +5 -5
  152. package/modules/@apostrophecms/ui/ui/apos/components/AposPager.vue +14 -8
  153. package/modules/@apostrophecms/ui/ui/apos/components/AposPagerDots.vue +2 -1
  154. package/modules/@apostrophecms/ui/ui/apos/components/AposSlat.vue +13 -12
  155. package/modules/@apostrophecms/ui/ui/apos/components/AposSlatList.vue +53 -59
  156. package/modules/@apostrophecms/ui/ui/apos/components/AposSpinner.vue +2 -2
  157. package/modules/@apostrophecms/ui/ui/apos/components/AposSubformPreview.vue +2 -2
  158. package/modules/@apostrophecms/ui/ui/apos/components/AposTag.vue +3 -2
  159. package/modules/@apostrophecms/ui/ui/apos/components/AposTagApply.vue +40 -35
  160. package/modules/@apostrophecms/ui/ui/apos/components/AposTagListItem.vue +2 -1
  161. package/modules/@apostrophecms/ui/ui/apos/components/AposToggle.vue +2 -2
  162. package/modules/@apostrophecms/ui/ui/apos/components/AposTree.vue +9 -11
  163. package/modules/@apostrophecms/ui/ui/apos/components/AposTreeHeader.vue +5 -3
  164. package/modules/@apostrophecms/ui/ui/apos/components/AposTreeRows.vue +129 -129
  165. package/modules/@apostrophecms/ui/ui/apos/composables/AposTheme.js +11 -0
  166. package/modules/@apostrophecms/ui/ui/apos/lib/click-outside-element.js +4 -4
  167. package/modules/@apostrophecms/ui/ui/apos/lib/i18next.js +56 -50
  168. package/modules/@apostrophecms/ui/ui/apos/lib/tooltip.js +191 -0
  169. package/modules/@apostrophecms/ui/ui/apos/lib/vue.js +19 -10
  170. package/modules/@apostrophecms/ui/ui/apos/mixins/AposAdvisoryLockMixin.js +1 -1
  171. package/modules/@apostrophecms/ui/ui/apos/scss/global/_tables.scss +1 -1
  172. package/modules/@apostrophecms/ui/ui/apos/scss/global/_theme.scss +1 -0
  173. package/modules/@apostrophecms/ui/ui/apos/scss/global/_tooltips.scss +6 -22
  174. package/modules/@apostrophecms/ui/ui/apos/scss/shared/_table-rows.scss +1 -1
  175. package/modules/@apostrophecms/widget-type/index.js +8 -2
  176. package/modules/@apostrophecms/widget-type/ui/apos/components/AposWidgetEditor.vue +26 -22
  177. package/modules/@apostrophecms/widget-type/ui/apos/mixins/AposWidgetMixin.js +4 -4
  178. package/package.json +31 -44
  179. package/test/attachments.js +5 -0
  180. package/test/schemas.js +138 -0
  181. package/test/translation.js +538 -0
  182. package/test-lib/util.js +21 -0
  183. package/modules/@apostrophecms/ui/ui/apos/lib/localized-v-tooltip.js +0 -63
  184. package/modules/@apostrophecms/ui/ui/apos/lib/tooltip-options.js +0 -13
@@ -27,8 +27,8 @@
27
27
  <AposButton
28
28
  type="default"
29
29
  label="apostrophe:cancel"
30
- @click="close"
31
30
  :modifiers="[ 'block' ]"
31
+ @click="close"
32
32
  />
33
33
  </div>
34
34
  </template>
@@ -49,12 +49,12 @@
49
49
  class="apos-wizard__step apos-wizard__step-select-content"
50
50
  >
51
51
  <AposInputRadio
52
+ v-model="wizard.values.toLocalize"
52
53
  :field="{
53
54
  name: 'toLocalize',
54
55
  label: 'apostrophe:selectContentToLocalize',
55
56
  choices: toLocalizeChoices
56
57
  }"
57
- v-model="wizard.values.toLocalize"
58
58
  />
59
59
  <p class="apos-wizard__help-text">
60
60
  <AposIndicator
@@ -71,20 +71,20 @@
71
71
  class="apos-wizard__step apos-wizard__step-select-locales"
72
72
  >
73
73
  <AposButton
74
- v-on="{ click: allSelected ? deselectAll : selectAll }"
75
74
  class="apos-locale-select-all"
76
75
  :label="allSelected
77
76
  ? $t('apostrophe:deselectAll')
78
77
  : $t('apostrophe:selectAll')"
79
78
  type="quiet"
80
79
  :modifiers="[ 'inline' ]"
80
+ v-on="{ click: allSelected ? deselectAll : selectAll }"
81
81
  />
82
82
  <AposInputString
83
+ ref="searchInput"
83
84
  v-model="searchValue"
84
85
  :field="searchField"
85
- @input="updateFilter"
86
86
  class="apos-locales-filter"
87
- ref="searchInput"
87
+ @update:model-value="updateFilter"
88
88
  />
89
89
  <transition-group
90
90
  tag="ul"
@@ -98,12 +98,12 @@
98
98
  >
99
99
  <AposButton
100
100
  type="primary"
101
- @click.prevent="removeLocale(loc)"
102
101
  class="apos-locale-button"
103
102
  :modifiers="[ 'small' ]"
104
103
  icon="close-icon"
105
104
  :icon-size="12"
106
105
  :label="loc.label"
106
+ @click.prevent="removeLocale(loc)"
107
107
  />
108
108
  </li>
109
109
  </transition-group>
@@ -136,13 +136,13 @@
136
136
  ({{ loc.name }})
137
137
  </span>
138
138
  <span
139
+ v-apos-tooltip="isLocalized(loc)
140
+ ? 'Localized'
141
+ : 'Not Yet Localized'"
139
142
  class="apos-locale-localized"
140
143
  :class="{
141
144
  'apos-state-is-localized': isLocalized(loc),
142
145
  }"
143
- v-apos-tooltip="isLocalized(loc)
144
- ? 'Localized'
145
- : 'Not Yet Localized'"
146
146
  />
147
147
  </span>
148
148
  </li>
@@ -155,9 +155,9 @@
155
155
  >
156
156
  <ul class="apos-selected-locales">
157
157
  <li
158
- class="apos-locale-item--selected"
159
158
  v-for="loc in selectedLocales"
160
159
  :key="loc.name"
160
+ class="apos-locale-item--selected"
161
161
  >
162
162
  <AposButton
163
163
  type="primary"
@@ -184,6 +184,7 @@
184
184
  </p>
185
185
 
186
186
  <AposInputRadio
187
+ v-model="wizard.values.relatedDocSettings"
187
188
  :field="{
188
189
  name: 'relatedDocSettings',
189
190
  choices: [
@@ -198,13 +199,11 @@
198
199
  },
199
200
  ],
200
201
  }"
201
- v-model="wizard.values.relatedDocSettings"
202
202
  />
203
-
204
203
  <AposInputCheckboxes
205
204
  v-if="relatedDocTypes.length"
206
- :field="relatedDocTypesField"
207
205
  v-model="wizard.values.relatedDocTypesToLocalize"
206
+ :field="relatedDocTypesField"
208
207
  />
209
208
  <p v-else class="apos-wizard__help-text">
210
209
  <AposIndicator
@@ -216,6 +215,46 @@
216
215
  {{ $t('apostrophe:noNewRelatedDocuments') }}
217
216
  </p>
218
217
  </div>
218
+ <div v-if="translationEnabled" class="apos-wizard__translation">
219
+ <p class="apos-wizard__translation-title">
220
+ <AposTranslationIndicator :size="18" />
221
+ <span class="apos-wizard__translation-title-text">
222
+ {{ $t('apostrophe:automaticTranslationSettings') }}
223
+ </span>
224
+ </p>
225
+ <AposCheckbox
226
+ v-model="wizard.values.translateContent.data"
227
+ :field="{ name: 'translate' }"
228
+ :choice="{
229
+ value: wizard.values.translateContent.data,
230
+ label: $t('apostrophe:automaticTranslationCheckbox')
231
+ }"
232
+ data-apos-test="localizationTranslationCheck"
233
+ />
234
+
235
+ <div v-if="translationErrMsg">
236
+ <!-- eslint-disable vue/no-v-html -->
237
+ <p
238
+ class="apos-wizard__translation-error"
239
+ data-apos-test="localizationTranslationErr"
240
+ v-html="translationErrMsg"
241
+ />
242
+ <!-- eslint-disable vue/no-v-html -->
243
+ <AposButton
244
+ v-if="translationShowRetry"
245
+ label="apostrophe:retry"
246
+ :modifiers="['quiet', 'no-motion']"
247
+ data-apos-test="localizationTranslationRetry"
248
+ @click="retryTranslationCheck()"
249
+ />
250
+ </div>
251
+ <div
252
+ v-else-if="translationShowLoader"
253
+ class="apos-wizard__translation-spinner"
254
+ >
255
+ <AposSpinner />
256
+ </div>
257
+ </div>
219
258
  </fieldset>
220
259
  </form>
221
260
  </template>
@@ -230,19 +269,19 @@
230
269
  <AposButton
231
270
  v-else
232
271
  type="primary"
233
- @click="goToNext()"
234
272
  icon="arrow-right-icon"
235
273
  :modifiers="['icon-right']"
236
274
  :disabled="!complete() || wizard.busy"
237
275
  :icon-size="12"
238
276
  label="apostrophe:next"
277
+ @click="goToNext()"
239
278
  />
240
279
  <AposButton
241
280
  v-if="!isFirstStep()"
242
281
  type="default"
243
282
  :disabled="wizard.busy"
244
- @click="goToPrevious()"
245
283
  label="apostrophe:back"
284
+ @click="goToPrevious()"
246
285
  />
247
286
  </template>
248
287
  </AposModalBody>
@@ -339,7 +378,10 @@ export default {
339
378
  toLocalize: { data: 'thisDocAndRelated' },
340
379
  toLocales: { data: this.locale ? [ this.locale ] : [] },
341
380
  relatedDocSettings: { data: 'localizeNewRelated' },
342
- relatedDocTypesToLocalize: { data: [] }
381
+ relatedDocTypesToLocalize: { data: [] },
382
+ translateContent: { data: false },
383
+ translateTargets: { data: [] },
384
+ translateProvider: { data: apos.translation.providers[0]?.name || null }
343
385
  }
344
386
  },
345
387
  fullDoc: this.doc,
@@ -370,7 +412,11 @@ export default {
370
412
  value: 'relatedDocsOnly',
371
413
  label: 'apostrophe:relatedDocsOnly'
372
414
  }
373
- ]
415
+ ],
416
+ translationEnabled: apos.modules['@apostrophecms/translation'].enabled,
417
+ translationErrMsg: null,
418
+ translationShowRetry: false,
419
+ translationShowLoader: false
374
420
  };
375
421
  },
376
422
  computed: {
@@ -429,7 +475,7 @@ export default {
429
475
  },
430
476
  visibleSections() {
431
477
  const self = this;
432
- const result = Object.entries(this.wizard.sections).filter(([ name, section ]) => {
478
+ const result = Object.entries(this.wizard.sections).filter(([ _, section ]) => {
433
479
  return section.if ? section.if.bind(self)() : true;
434
480
  }).map(([ name, section ]) => {
435
481
  return {
@@ -464,6 +510,9 @@ export default {
464
510
  'wizard.values.toLocalize.data'() {
465
511
  this.updateRelatedDocs();
466
512
  },
513
+ async 'wizard.values.translateContent.data'(value) {
514
+ await this.checkAvailableTranslations(value);
515
+ },
467
516
  selectedLocales() {
468
517
  this.updateRelatedDocs();
469
518
  },
@@ -517,6 +566,13 @@ export default {
517
566
  },
518
567
  goToPrevious() {
519
568
  this.wizard.step = this.previousStepName;
569
+ this.uncheckTranslate();
570
+ },
571
+ uncheckTranslate() {
572
+ this.wizard.values.translateContent.data = false;
573
+ this.wizard.values.translateTargets.data = [];
574
+ this.translationErrMsg = null;
575
+ this.translationShowRetry = false;
520
576
  },
521
577
  goToNext() {
522
578
  this.goTo(this.nextStepName);
@@ -545,16 +601,26 @@ export default {
545
601
  return !!this.localized[locale.name];
546
602
  },
547
603
  selectAll() {
548
- this.wizard.values.toLocales.data = this.locales.filter(locale => !this.isCurrentLocale(locale) && this.canEditLocale(locale));
604
+ this.wizard.values.toLocales.data = this.locales
605
+ .filter(locale => !this.isCurrentLocale(locale) && this.canEditLocale(locale));
549
606
  },
550
607
  deselectAll() {
551
608
  this.wizard.values.toLocales.data = [];
552
609
  },
553
610
  toggleLocale(locale) {
554
- if (!this.isSelected(locale) && !this.isCurrentLocale(locale) && this.canEditLocale(locale)) {
555
- this.wizard.values.toLocales.data.push(locale);
611
+ if (
612
+ !this.isSelected(locale) &&
613
+ !this.isCurrentLocale(locale) &&
614
+ this.canEditLocale(locale)
615
+ ) {
616
+ this.wizard.values.toLocales.data = [
617
+ ...this.wizard.values.toLocales.data,
618
+ locale
619
+ ];
620
+
556
621
  } else if (this.isSelected(locale)) {
557
- this.wizard.values.toLocales.data = this.wizard.values.toLocales.data.filter(l => l !== locale);
622
+ this.wizard.values.toLocales.data = this.wizard.values.toLocales.data
623
+ .filter(l => l !== locale);
558
624
  }
559
625
  // Reset search filter
560
626
  if (this.filteredLocales.length < 2) {
@@ -652,6 +718,10 @@ export default {
652
718
  toLocale: locale.name,
653
719
  update: (doc._id === this.fullDoc._id) || !(this.wizard.values.relatedDocSettings.data === 'localizeNewRelated')
654
720
  },
721
+ qs: {
722
+ aposTranslateTargets: this.wizard.values.translateTargets.data,
723
+ aposTranslateProvider: this.wizard.values.translateProvider.data
724
+ },
655
725
  busy: true
656
726
  });
657
727
 
@@ -788,7 +858,11 @@ export default {
788
858
  // never be considered "related" to other pages simply because
789
859
  // of navigation links, the feature is meant for pieces that feel more like
790
860
  // part of the document being localized)
791
- return related.filter(doc => apos.modules[doc.type].relatedDocument !== false);
861
+ // We also remove non localized content like users
862
+ return related.filter(doc => {
863
+ return apos.modules[doc.type].relatedDocument !== false &&
864
+ apos.modules[doc.type].localized !== false;
865
+ });
792
866
  }
793
867
  },
794
868
  async updateRelatedDocs() {
@@ -822,6 +896,77 @@ export default {
822
896
  }
823
897
  this.relatedDocs = relatedDocs;
824
898
  this.wizard.busy = status;
899
+ },
900
+ wait(time) {
901
+ return new Promise((resolve) => {
902
+ setTimeout(() => {
903
+ resolve();
904
+ }, time);
905
+ });
906
+ },
907
+ async retryTranslationCheck() {
908
+ await this.checkAvailableTranslations(false);
909
+ this.translationShowLoader = true;
910
+ await this.wait(500);
911
+ await this.checkAvailableTranslations(true);
912
+ this.translationShowLoader = false;
913
+ },
914
+ async checkAvailableTranslations(value) {
915
+ if (!value) {
916
+ this.translationErrMsg = null;
917
+ this.translationShowRetry = false;
918
+ this.wizard.values.translateTargets.data = [];
919
+ return;
920
+ }
921
+ const [ sourceLocale ] = this.doc.aposLocale.split(':');
922
+ const targets = this.wizard.values.toLocales.data;
923
+
924
+ let response;
925
+ try {
926
+ response = await apos.http.get(`${apos.translation.action}/languages`, {
927
+ qs: {
928
+ provider: this.wizard.values.translateProvider.data,
929
+ source: [ sourceLocale ],
930
+ target: targets.map(({ name }) => name)
931
+ }
932
+ });
933
+ } catch (err) {
934
+ console.error('An error happened while getting available languages: ', err);
935
+ this.wizard.values.translateTargets.data = [];
936
+ this.translationErrMsg = this.$t('apostrophe:automaticTranslationErrMsg');
937
+ this.translationShowRetry = true;
938
+ return;
939
+ }
940
+
941
+ const unavailableSource = !response.source[0].supported;
942
+ const unavailableTargetsLabels = response.target
943
+ .filter(({ supported }) => !supported)
944
+ .map(({ code }) => targets.find((locale) => locale.name === code)?.label || code);
945
+
946
+ if (unavailableSource) {
947
+ const sourceLabel = this.moduleOptions.locales[sourceLocale]?.label;
948
+ this.translationErrMsg = this.$t('apostrophe:automaticTranslationSourceErrMsg', { source: sourceLabel });
949
+ this.wizard.values.translateTargets.data = [];
950
+ return;
951
+ }
952
+
953
+ if (unavailableTargetsLabels.length) {
954
+ const isPlural = unavailableTargetsLabels.length > 1;
955
+ this.translationErrMsg = this.$t(
956
+ `apostrophe:automaticTranslationTargetErrMsg${isPlural ? '_plural' : ''}`,
957
+ { targets: unavailableTargetsLabels.join(', ') }
958
+ );
959
+ }
960
+
961
+ if (unavailableTargetsLabels.length >= targets.length) {
962
+ this.wizard.values.translateTargets.data = [];
963
+ return;
964
+ }
965
+
966
+ this.wizard.values.translateTargets.data = response.target
967
+ .filter(({ supported }) => supported)
968
+ .map(({ code }) => code);
969
+
825
970
  }
826
971
  }
827
972
  };
@@ -831,7 +976,7 @@ export default {
831
976
  .apos-i18n-localize {
832
977
  @include type-base;
833
978
 
834
- ::v-deep .apos-modal__inner {
979
+ :deep(.apos-modal__inner) {
835
980
  $width: 565px;
836
981
  $vertical-spacing: 95px;
837
982
  $horizontal-spacing: calc(calc(100vw - #{$width}) / 2);
@@ -843,20 +988,20 @@ export default {
843
988
  height: calc(100vh - #{$vertical-spacing * 2});
844
989
  }
845
990
 
846
- ::v-deep .apos-modal__main--with-left-rail {
991
+ :deep(.apos-modal__main--with-left-rail) {
847
992
  grid-template-columns: 30% 70%;
848
993
  }
849
994
 
850
- ::v-deep .apos-modal__body-inner {
995
+ :deep(.apos-modal__body-inner) {
851
996
  padding: $spacing-triple $spacing-triple $spacing-double;
852
997
  }
853
998
 
854
- ::v-deep .apos-wizard__content .apos-modal__body-footer {
999
+ :deep(.apos-wizard__content .apos-modal__body-footer) {
855
1000
  flex-direction: row-reverse;
856
1001
  border-top: 1px solid var(--a-base-9);
857
1002
  }
858
1003
 
859
- ::v-deep .apos-busy__spinner {
1004
+ :deep(.apos-busy__spinner) {
860
1005
  display: inline-block;
861
1006
  }
862
1007
  }
@@ -890,7 +1035,7 @@ export default {
890
1035
  border: none;
891
1036
  }
892
1037
 
893
- ::v-deep .apos-field--toLocalize {
1038
+ :deep(.apos-field--toLocalize) {
894
1039
  margin-bottom: $spacing-triple;
895
1040
  }
896
1041
 
@@ -901,7 +1046,7 @@ export default {
901
1046
  font-weight: 400;
902
1047
  color: var(--a-base-3);
903
1048
 
904
- ::v-deep .material-design-icon {
1049
+ :deep(.material-design-icon) {
905
1050
  position: relative;
906
1051
  top: 3px;
907
1052
  color: var(--a-base-5);
@@ -944,7 +1089,7 @@ export default {
944
1089
  }
945
1090
  }
946
1091
 
947
- .apos-locale-button ::v-deep .apos-button {
1092
+ .apos-locale-button :deep(.apos-button) {
948
1093
  font-size: var(--a-type-small);
949
1094
  }
950
1095
 
@@ -1011,9 +1156,12 @@ export default {
1011
1156
  }
1012
1157
  }
1013
1158
 
1159
+ .apos-wizard__step :deep(.apos-field--relatedDocTypesToLocalize) {
1160
+ margin-top: $spacing-triple;
1161
+ }
1014
1162
  .apos-wizard__step {
1015
- .apos-field__wrapper:not(:last-of-type) {
1016
- margin-bottom: $spacing-triple;
1163
+ .apos-field__wrapper {
1164
+ margin-bottom: $spacing-double;
1017
1165
  }
1018
1166
  }
1019
1167
 
@@ -1056,4 +1204,32 @@ export default {
1056
1204
  .apos-locale-name {
1057
1205
  text-transform: uppercase;
1058
1206
  }
1207
+
1208
+ .apos-wizard__translation {
1209
+ margin-top: 30px;
1210
+ }
1211
+
1212
+ .apos-wizard__translation-title {
1213
+ @include type-label;
1214
+
1215
+ display: flex;
1216
+ align-items: center;
1217
+ border-bottom: 1px solid var(--a-base-8);
1218
+ padding-bottom: 8px;
1219
+ }
1220
+
1221
+ .apos-wizard__translation-title-text {
1222
+ margin-left: 7px;
1223
+ }
1224
+
1225
+ .apos-wizard__translation-error {
1226
+ @include type-label;
1227
+ color: var(--a-danger);
1228
+ }
1229
+
1230
+ .apos-wizard__translation-spinner {
1231
+ margin-top: 20px;
1232
+ display: flex;
1233
+ justify-content: center;
1234
+ }
1059
1235
  </style>
@@ -27,7 +27,7 @@
27
27
  {{ docType(item.doc) }}
28
28
  </span>
29
29
  </div>
30
- <div class="apos-confirm__notification-detail" v-if="item.detail">
30
+ <div v-if="item.detail" class="apos-confirm__notification-detail">
31
31
  {{ $t(item.detail) }}
32
32
  </div>
33
33
  </div>
@@ -36,8 +36,8 @@
36
36
  </template>
37
37
 
38
38
  <script>
39
- import CheckIcon from 'vue-material-design-icons/Check.vue';
40
- import CancelIcon from 'vue-material-design-icons/Cancel.vue';
39
+ import CheckIcon from '@apostrophecms/vue-material-design-icons/Check.vue';
40
+ import CancelIcon from '@apostrophecms/vue-material-design-icons/Cancel.vue';
41
41
 
42
42
  export default {
43
43
  name: 'AposI18nLocalizeErrors',
@@ -1,15 +1,15 @@
1
1
  <template>
2
2
  <div
3
3
  class="apos-image-cropper"
4
- @click="onImageClick"
5
4
  :style="{
6
5
  height: cropperHeight
7
6
  }"
7
+ @click="onImageClick"
8
8
  >
9
9
  <span
10
- class="apos-image-focal-point"
11
10
  ref="focalPoint"
12
11
  v-apos-tooltip="'apostrophe:focalPoint'"
12
+ class="apos-image-focal-point"
13
13
  @mousedown="onFocalPointMouseDown"
14
14
  />
15
15
  <cropper
@@ -18,13 +18,13 @@
18
18
  ? attachment._urls.uncropped.original
19
19
  : attachment._urls.original"
20
20
  :debounce="0"
21
- @ready="onCropperReady"
22
- @change="onCropperChange"
23
21
  :default-size="defaultSize"
24
22
  :default-position="defaultPosition"
25
23
  :stencil-props="stencilProps"
26
24
  :min-width="minSize[0]"
27
25
  :min-height="minSize[1]"
26
+ @ready="onCropperReady"
27
+ @change="onCropperChange"
28
28
  />
29
29
  </div>
30
30
  </template>
@@ -127,7 +127,7 @@ export default {
127
127
  left: this.docFields.data.left
128
128
  };
129
129
  },
130
- beforeDestroy() {
130
+ beforeUnmount() {
131
131
  this.$refs.focalPoint.removeEventListener('mousedown', this.onFocalPointMouseDown);
132
132
  window.removeEventListener('resize', this.onScreenResizeDebounced);
133
133
  },
@@ -65,12 +65,12 @@
65
65
  </label>
66
66
  <input
67
67
  :value="docFields.data.width"
68
- @input="inputWidth"
69
- @blur="blurInput"
70
68
  class="apos-input apos-input--text"
71
69
  type="number"
72
70
  :min="minWidth"
73
71
  :max="maxWidth"
72
+ @input="inputWidth"
73
+ @blur="blurInput"
74
74
  >
75
75
  </div>
76
76
  <div class="apos-field">
@@ -79,12 +79,12 @@
79
79
  </label>
80
80
  <input
81
81
  :value="docFields.data.height"
82
- @input="inputHeight"
83
- @blur="blurInput"
84
82
  class="apos-input apos-input--text"
85
83
  type="number"
86
84
  :min="minHeight"
87
85
  :max="maxHeight"
86
+ @input="inputHeight"
87
+ @blur="blurInput"
88
88
  >
89
89
  </div>
90
90
  </div>
@@ -122,7 +122,7 @@ export default {
122
122
  type: Array,
123
123
  default: () => ([])
124
124
  },
125
- value: {
125
+ modelValue: {
126
126
  type: Object,
127
127
  default: null
128
128
  },
@@ -141,7 +141,7 @@ export default {
141
141
  const minSize = this.getMinSize();
142
142
 
143
143
  return {
144
- original: this.value,
144
+ original: this.modelValue,
145
145
  docFields: {
146
146
  data: this.setDataValues()
147
147
  },
@@ -6,20 +6,25 @@
6
6
 
7
7
  <template>
8
8
  <AposModal
9
- :modal="modal" :modal-title="modalTitle"
9
+ :modal="modal"
10
+ :modal-title="modalTitle"
10
11
  class="apos-media-manager"
11
- @inactive="modal.active = false" @show-modal="modal.showModal = true"
12
- @esc="confirmAndCancel" @no-modal="$emit('safe-close')"
12
+ @inactive="modal.active = false"
13
+ @show-modal="modal.showModal = true"
14
+ @esc="confirmAndCancel"
15
+ @no-modal="$emit('safe-close')"
13
16
  >
14
17
  <template v-if="relationshipField" #secondaryControls>
15
18
  <AposButton
16
- type="default" label="apostrophe:cancel"
19
+ type="default"
20
+ label="apostrophe:cancel"
17
21
  @click="confirmAndCancel"
18
22
  />
19
23
  </template>
20
24
  <template v-else #secondaryControls>
21
25
  <AposButton
22
- type="default" label="apostrophe:exit"
26
+ type="default"
27
+ label="apostrophe:exit"
23
28
  @click="confirmAndCancel"
24
29
  />
25
30
  </template>
@@ -68,22 +73,22 @@
68
73
  <template #bodyMain>
69
74
  <AposMediaManagerDisplay
70
75
  ref="display"
76
+ v-model:checked="checked"
71
77
  :accept="accept"
72
78
  :items="items"
73
79
  :module-options="moduleOptions"
80
+ :max-reached="maxReached()"
81
+ :options="{
82
+ disableUnchecked: maxReached(),
83
+ hideCheckboxes: !relationshipField
84
+ }"
74
85
  @edit="updateEditing"
75
- v-model="checked"
76
86
  @select="select"
77
87
  @select-series="selectSeries"
78
88
  @select-another="selectAnother"
79
89
  @upload-started="uploading = true"
80
90
  @upload-complete="completeUploading"
81
91
  @create-placeholder="createPlaceholder"
82
- :max-reached="maxReached()"
83
- :options="{
84
- disableUnchecked: maxReached(),
85
- hideCheckboxes: !relationshipField
86
- }"
87
92
  />
88
93
  </template>
89
94
  </AposModalBody>
@@ -100,13 +105,15 @@
100
105
  :selected="selected"
101
106
  :is-modified="isModified"
102
107
  :module-labels="moduleLabels"
103
- @back="updateEditing(null)" @saved="updateMedia"
108
+ @back="updateEditing(null)"
109
+ @saved="updateMedia"
104
110
  @modified="editorModified"
105
111
  />
106
112
  <AposMediaManagerSelections
107
- :items="selected"
108
- @clear="clearSelected" @edit="updateEditing"
109
113
  v-show="!editing"
114
+ :items="selected"
115
+ @clear="clearSelected"
116
+ @edit="updateEditing"
110
117
  />
111
118
  </div>
112
119
  </AposModalRail>
@@ -233,7 +240,7 @@ export default {
233
240
  apos.bus.$on('content-changed', this.onContentChanged);
234
241
  apos.bus.$on('command-menu-manager-close', this.confirmAndCancel);
235
242
  },
236
- destroyed() {
243
+ unmounted() {
237
244
  apos.bus.$off('content-changed', this.onContentChanged);
238
245
  apos.bus.$off('command-menu-manager-close', this.confirmAndCancel);
239
246
  },
@@ -451,7 +458,7 @@ export default {
451
458
  </script>
452
459
 
453
460
  <style lang="scss" scoped>
454
- .apos-media-manager ::v-deep .apos-media-manager-toolbar {
461
+ .apos-media-manager :deep(.apos-media-manager-toolbar) {
455
462
  z-index: $z-index-manager-toolbar;
456
463
  position: relative;
457
464
  }