@firecms/core 3.2.0 → 3.3.0-canary.2064433

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 (193) hide show
  1. package/dist/app/AppBar.d.ts +1 -1
  2. package/dist/app/Drawer.d.ts +1 -1
  3. package/dist/components/AIIcon.d.ts +3 -2
  4. package/dist/components/ArrayContainer.d.ts +3 -3
  5. package/dist/components/CircularProgressCenter.d.ts +2 -1
  6. package/dist/components/ClearFilterSortButton.d.ts +1 -1
  7. package/dist/components/ConfirmationDialog.d.ts +1 -1
  8. package/dist/components/DeleteEntityDialog.d.ts +2 -1
  9. package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +1 -1
  10. package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +2 -1
  11. package/dist/components/EntityCollectionTable/fields/TableReferenceField.d.ts +1 -1
  12. package/dist/components/EntityCollectionTable/fields/TableStorageUpload.d.ts +2 -2
  13. package/dist/components/EntityCollectionTable/internal/CollectionTableToolbar.d.ts +1 -1
  14. package/dist/components/EntityCollectionTable/internal/EntityTableCellActions.d.ts +1 -1
  15. package/dist/components/EntityCollectionTable/internal/popup_field/PopupFormField.d.ts +4 -3
  16. package/dist/components/EntityCollectionView/Board.d.ts +2 -1
  17. package/dist/components/EntityCollectionView/BoardColumnTitle.d.ts +1 -1
  18. package/dist/components/EntityCollectionView/BoardSortableList.d.ts +1 -1
  19. package/dist/components/EntityCollectionView/CollectionDataErrorBanner.d.ts +2 -1
  20. package/dist/components/EntityCollectionView/EntityBoardCard.d.ts +1 -1
  21. package/dist/components/EntityCollectionView/EntityCard.d.ts +2 -1
  22. package/dist/components/EntityCollectionView/EntityCollectionBoardView.d.ts +1 -1
  23. package/dist/components/EntityCollectionView/EntityCollectionCardView.d.ts +1 -1
  24. package/dist/components/EntityCollectionView/EntityCollectionViewActions.d.ts +2 -1
  25. package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +2 -1
  26. package/dist/components/EntityCollectionView/FiltersDialog.d.ts +2 -1
  27. package/dist/components/EntityCollectionView/ViewModeToggle.d.ts +2 -1
  28. package/dist/components/EntityJsonPreview.d.ts +2 -1
  29. package/dist/components/EntityPreview.d.ts +1 -1
  30. package/dist/components/EntityView.d.ts +2 -1
  31. package/dist/components/ErrorBoundary.d.ts +1 -1
  32. package/dist/components/ErrorTooltip.d.ts +2 -1
  33. package/dist/components/FieldCaption.d.ts +1 -1
  34. package/dist/components/FireCMSLogo.d.ts +1 -1
  35. package/dist/components/HomePage/DefaultHomePage.d.ts +1 -1
  36. package/dist/components/HomePage/FavouritesView.d.ts +1 -1
  37. package/dist/components/HomePage/HomePageDnD.d.ts +4 -4
  38. package/dist/components/HomePage/NavigationCardBinding.d.ts +2 -1
  39. package/dist/components/HomePage/NavigationGroup.d.ts +2 -2
  40. package/dist/components/HomePage/RenameGroupDialog.d.ts +2 -1
  41. package/dist/components/HomePage/SmallNavigationCard.d.ts +1 -1
  42. package/dist/components/LanguageToggle.d.ts +2 -1
  43. package/dist/components/NotFoundPage.d.ts +2 -1
  44. package/dist/components/PropertyCollectionView.d.ts +2 -1
  45. package/dist/components/PropertyIdCopyTooltip.d.ts +2 -2
  46. package/dist/components/ReferenceTable/ReferenceSelectionTable.d.ts +1 -1
  47. package/dist/components/ReferenceWidget.d.ts +2 -1
  48. package/dist/components/SearchIconsView.d.ts +2 -1
  49. package/dist/components/SelectableTable/SelectableTable.d.ts +1 -1
  50. package/dist/components/SelectableTable/filters/BooleanFilterField.d.ts +2 -1
  51. package/dist/components/SelectableTable/filters/DateTimeFilterField.d.ts +2 -1
  52. package/dist/components/SelectableTable/filters/ReferenceFilterField.d.ts +2 -1
  53. package/dist/components/SelectableTable/filters/StringNumberFilterField.d.ts +2 -1
  54. package/dist/components/UnsavedChangesDialog.d.ts +1 -1
  55. package/dist/components/UserDisplay.d.ts +1 -1
  56. package/dist/components/VirtualTable/VirtualTableHeader.d.ts +1 -0
  57. package/dist/components/VirtualTable/VirtualTableHeaderRow.d.ts +2 -1
  58. package/dist/components/VirtualTable/VirtualTableProps.d.ts +6 -1
  59. package/dist/components/VirtualTable/fields/VirtualTableDateField.d.ts +1 -1
  60. package/dist/components/VirtualTable/fields/VirtualTableInput.d.ts +2 -1
  61. package/dist/components/VirtualTable/fields/VirtualTableNumberInput.d.ts +2 -1
  62. package/dist/components/VirtualTable/fields/VirtualTableSelect.d.ts +1 -1
  63. package/dist/components/VirtualTable/fields/VirtualTableSwitch.d.ts +2 -1
  64. package/dist/components/VirtualTable/fields/VirtualTableUserSelect.d.ts +1 -1
  65. package/dist/components/VirtualTable/types.d.ts +1 -0
  66. package/dist/core/DefaultAppBar.d.ts +1 -1
  67. package/dist/core/DefaultDrawer.d.ts +2 -2
  68. package/dist/core/DrawerNavigationGroup.d.ts +1 -1
  69. package/dist/core/DrawerNavigationItem.d.ts +1 -1
  70. package/dist/core/EntityEditView.d.ts +2 -2
  71. package/dist/core/EntityEditViewFormActions.d.ts +2 -1
  72. package/dist/core/EntitySidePanel.d.ts +2 -1
  73. package/dist/core/FireCMS.d.ts +2 -1
  74. package/dist/core/FireCMSRouter.d.ts +1 -1
  75. package/dist/core/SideDialogs.d.ts +1 -1
  76. package/dist/editor/components/SlashCommandMenu.d.ts +2 -1
  77. package/dist/editor/editor.d.ts +1 -1
  78. package/dist/editor/selectors/color-selector.d.ts +1 -1
  79. package/dist/editor/selectors/link-selector.d.ts +1 -1
  80. package/dist/editor/selectors/node-selector.d.ts +1 -1
  81. package/dist/editor/selectors/text-buttons.d.ts +1 -1
  82. package/dist/form/EntityForm.d.ts +1 -1
  83. package/dist/form/EntityFormActions.d.ts +1 -1
  84. package/dist/form/components/CustomIdField.d.ts +2 -1
  85. package/dist/form/components/FieldHelperText.d.ts +1 -1
  86. package/dist/form/components/FormEntry.d.ts +1 -1
  87. package/dist/form/components/FormLayout.d.ts +1 -1
  88. package/dist/form/components/LabelWithIconAndTooltip.d.ts +1 -1
  89. package/dist/form/components/LocalChangesMenu.d.ts +2 -1
  90. package/dist/form/components/StorageItemPreview.d.ts +2 -1
  91. package/dist/form/components/StorageUploadProgress.d.ts +2 -1
  92. package/dist/form/field_bindings/ArrayCustomShapedFieldBinding.d.ts +2 -1
  93. package/dist/form/field_bindings/ArrayOfReferencesFieldBinding.d.ts +2 -1
  94. package/dist/form/field_bindings/BlockFieldBinding.d.ts +2 -1
  95. package/dist/form/field_bindings/DateTimeFieldBinding.d.ts +2 -1
  96. package/dist/form/field_bindings/KeyValueFieldBinding.d.ts +2 -1
  97. package/dist/form/field_bindings/MapFieldBinding.d.ts +2 -1
  98. package/dist/form/field_bindings/MarkdownEditorFieldBinding.d.ts +3 -2
  99. package/dist/form/field_bindings/MultiSelectFieldBinding.d.ts +2 -1
  100. package/dist/form/field_bindings/ReadOnlyFieldBinding.d.ts +2 -1
  101. package/dist/form/field_bindings/ReferenceAsStringFieldBinding.d.ts +2 -1
  102. package/dist/form/field_bindings/ReferenceFieldBinding.d.ts +2 -1
  103. package/dist/form/field_bindings/RepeatFieldBinding.d.ts +2 -1
  104. package/dist/form/field_bindings/SelectFieldBinding.d.ts +2 -1
  105. package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +3 -2
  106. package/dist/form/field_bindings/SwitchFieldBinding.d.ts +2 -1
  107. package/dist/form/field_bindings/TextFieldBinding.d.ts +2 -1
  108. package/dist/form/field_bindings/UserSelectFieldBinding.d.ts +2 -1
  109. package/dist/i18n/FireCMSi18nProvider.d.ts +2 -2
  110. package/dist/index.d.ts +1 -0
  111. package/dist/index.es.js +24457 -23726
  112. package/dist/index.es.js.map +1 -1
  113. package/dist/index.umd.js +22959 -22228
  114. package/dist/index.umd.js.map +1 -1
  115. package/dist/preview/components/ArrayEnumPreview.d.ts +2 -1
  116. package/dist/preview/components/AsyncPreviewComponent.d.ts +1 -1
  117. package/dist/preview/components/EmptyValue.d.ts +2 -1
  118. package/dist/preview/components/EnumValuesChip.d.ts +1 -1
  119. package/dist/preview/components/ImagePreview.d.ts +2 -1
  120. package/dist/preview/components/ReferencePreview.d.ts +1 -1
  121. package/dist/preview/components/StorageThumbnail.d.ts +1 -1
  122. package/dist/preview/components/UserPreview.d.ts +2 -1
  123. package/dist/preview/property_previews/ArrayOfMapsPreview.d.ts +2 -1
  124. package/dist/preview/property_previews/ArrayOfReferencesPreview.d.ts +1 -1
  125. package/dist/preview/property_previews/ArrayOfStorageComponentsPreview.d.ts +2 -1
  126. package/dist/preview/property_previews/ArrayOfStringsPreview.d.ts +2 -1
  127. package/dist/preview/property_previews/ArrayOneOfPreview.d.ts +2 -1
  128. package/dist/preview/property_previews/ArrayPropertyEnumPreview.d.ts +1 -1
  129. package/dist/preview/property_previews/ArrayPropertyPreview.d.ts +2 -1
  130. package/dist/preview/property_previews/MapPropertyPreview.d.ts +3 -2
  131. package/dist/preview/property_previews/SkeletonPropertyComponent.d.ts +5 -4
  132. package/dist/routes/FireCMSRoute.d.ts +2 -1
  133. package/dist/types/collections.d.ts +38 -0
  134. package/dist/types/properties.d.ts +9 -8
  135. package/dist/types/translations.d.ts +23 -0
  136. package/dist/util/index.d.ts +1 -0
  137. package/dist/util/lazy_eager.d.ts +7 -0
  138. package/dist/util/objects.d.ts +1 -0
  139. package/dist/util/property_utils.d.ts +1 -1
  140. package/package.json +5 -5
  141. package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +9 -3
  142. package/src/components/EntityCollectionTable/internal/common.tsx +2 -2
  143. package/src/components/EntityCollectionView/EntityCollectionView.tsx +3 -5
  144. package/src/components/EntityJsonPreview.tsx +2 -1
  145. package/src/components/ErrorBoundary.tsx +3 -3
  146. package/src/components/VirtualTable/VirtualTable.tsx +5 -3
  147. package/src/components/VirtualTable/VirtualTableHeader.tsx +9 -8
  148. package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +8 -3
  149. package/src/components/VirtualTable/VirtualTableProps.tsx +7 -1
  150. package/src/components/VirtualTable/types.tsx +1 -0
  151. package/src/core/DrawerNavigationGroup.tsx +1 -1
  152. package/src/core/EntityEditView.tsx +50 -5
  153. package/src/core/EntitySidePanel.tsx +2 -1
  154. package/src/core/field_configs.tsx +4 -2
  155. package/src/editor/editor.tsx +20 -1
  156. package/src/editor/markdown.ts +89 -1
  157. package/src/form/EntityForm.tsx +64 -4
  158. package/src/form/PropertyFieldBinding.tsx +4 -3
  159. package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +18 -5
  160. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +18 -5
  161. package/src/form/field_bindings/BlockFieldBinding.tsx +21 -7
  162. package/src/form/field_bindings/DateTimeFieldBinding.tsx +1 -1
  163. package/src/form/field_bindings/KeyValueFieldBinding.tsx +23 -6
  164. package/src/form/field_bindings/MapFieldBinding.tsx +23 -8
  165. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +43 -20
  166. package/src/form/field_bindings/MultiSelectFieldBinding.tsx +15 -1
  167. package/src/form/field_bindings/ReferenceAsStringFieldBinding.tsx +25 -11
  168. package/src/form/field_bindings/ReferenceFieldBinding.tsx +25 -11
  169. package/src/form/field_bindings/RepeatFieldBinding.tsx +18 -5
  170. package/src/form/field_bindings/SelectFieldBinding.tsx +7 -5
  171. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +24 -7
  172. package/src/form/field_bindings/SwitchFieldBinding.tsx +31 -14
  173. package/src/form/field_bindings/TextFieldBinding.tsx +10 -7
  174. package/src/form/field_bindings/UserSelectFieldBinding.tsx +7 -5
  175. package/src/index.ts +1 -0
  176. package/src/internal/useBuildSideEntityController.tsx +1 -1
  177. package/src/locales/de.ts +28 -1
  178. package/src/locales/en.ts +27 -0
  179. package/src/locales/es.ts +28 -1
  180. package/src/locales/fr.ts +28 -1
  181. package/src/locales/hi.ts +28 -1
  182. package/src/locales/it.ts +28 -1
  183. package/src/locales/pt.ts +28 -1
  184. package/src/preview/PropertyPreview.tsx +6 -5
  185. package/src/preview/components/ReferencePreview.tsx +2 -1
  186. package/src/preview/property_previews/MapPropertyPreview.tsx +49 -27
  187. package/src/routes/FireCMSRoute.tsx +63 -54
  188. package/src/types/collections.ts +40 -0
  189. package/src/types/properties.ts +11 -10
  190. package/src/types/translations.ts +27 -0
  191. package/src/util/index.ts +1 -0
  192. package/src/util/lazy_eager.tsx +33 -0
  193. package/src/util/objects.ts +15 -0
package/src/locales/fr.ts CHANGED
@@ -437,6 +437,8 @@ export const fr: FireCMSTranslations = {
437
437
  cms_users: "Utilisateurs du CMS",
438
438
  roles_menu: "Rôles",
439
439
  project_settings: "Paramètres du projet",
440
+ firestore_explorer: "Explorateur Firestore",
441
+ explore_your_firestore_data: "Explorez vos données Firestore",
440
442
 
441
443
  // ─── FireCMS Cloud Login ──────────────────────────────────────
442
444
  build_admin_panel_in_minutes: "Créez votre panneau d'administration Firebase en quelques minutes",
@@ -678,6 +680,17 @@ export const fr: FireCMSTranslations = {
678
680
  settings_appcheck_updated: "AppCheck mis à jour",
679
681
  settings_appcheck_error: "Erreur lors de la mise à jour d'AppCheck",
680
682
 
683
+ // --- Permission Error View ---
684
+ missing_firestore_security_rules: "Règles de sécurité Firestore manquantes",
685
+ firecms_cloud_requires_security_rule: "FireCMS Cloud nécessite une règle de sécurité spécifique dans votre Firestore pour accorder l'accès aux utilisateurs authentifiés. La collection",
686
+ cannot_be_accessed_without_it: "ne peut pas être consultée sans elle.",
687
+ required_security_rule: "Règle de sécurité requise",
688
+ fix_automatically: "Corriger automatiquement",
689
+ open_firebase_rules: "Ouvrir les règles Firebase",
690
+ security_rules_updated_successfully: "Règles de sécurité mises à jour avec succès! Veuillez rafraîchir la page pour charger vos données.",
691
+ sec_rules_fixing: "Correction...",
692
+ sec_rules_fixed: "Corrigé!",
693
+
681
694
  // ─── Text Search Dialog ─────────────────────────────────────
682
695
  text_search_dialog_title: "Activer la recherche de texte",
683
696
  text_search_local_not_recommended: "La recherche de texte locale n'est pas recommandée pour les grandes collections.",
@@ -687,5 +700,19 @@ export const fr: FireCMSTranslations = {
687
700
  text_search_own_implementation: "Vous avez implémenté votre propre contrôleur de recherche de texte. Vous pouvez activer la recherche de texte pour votre collection.",
688
701
  text_search_enable_for_collection: "Activer pour cette collection",
689
702
  text_search_enable_for_project: "Activer pour le projet",
690
- text_search_enabled_snackbar: "Recherche de texte locale activée"
703
+ text_search_enabled_snackbar: "Recherche de texte locale activée",
704
+
705
+ // ─── GCP Marketplace ─────────────────────────────────────────
706
+ marketplace_managed_by_gcp: "Géré via GCP Marketplace",
707
+ marketplace_billing_note: "Votre abonnement est géré via Google Cloud Marketplace. Les modifications de plan, la facturation et l'annulation sont gérées dans la console GCP.",
708
+ marketplace_manage_in_gcp_console: "Gérer dans la console GCP",
709
+ marketplace_plan_changes_note: "Pour modifier votre plan ou annuler, visitez vos commandes GCP Marketplace.",
710
+ marketplace_welcome_title: "Bienvenue depuis GCP Marketplace !",
711
+ marketplace_welcome_subtitle: "Votre abonnement Google Cloud Marketplace est actif. Sélectionnez un projet existant ou créez-en un nouveau pour le lier.",
712
+ marketplace_select_or_create_project: "Sélectionner ou créer un projet",
713
+ marketplace_link_project: "Lier le projet",
714
+ marketplace_linking: "Liaison du projet en cours…",
715
+ marketplace_link_success: "Projet lié avec succès ! Redirection…",
716
+ marketplace_link_error: "Erreur lors de la liaison du projet. Veuillez réessayer.",
717
+ marketplace_no_account_id: "Aucun identifiant de compte GCP Marketplace trouvé. Veuillez commencer depuis GCP Marketplace.",
691
718
  };
package/src/locales/hi.ts CHANGED
@@ -437,6 +437,8 @@ export const hi: FireCMSTranslations = {
437
437
  cms_users: "CMS उपयोगकर्ता",
438
438
  roles_menu: "भूमिकाएँ",
439
439
  project_settings: "परियोजना सेटिंग",
440
+ firestore_explorer: "Firestore एक्सप्लोरर",
441
+ explore_your_firestore_data: "अपने Firestore डेटा का अन्वेषण करें",
440
442
 
441
443
  // ─── FireCMS Cloud Login ──────────────────────────────────────
442
444
  build_admin_panel_in_minutes: "मिनटों में अपना Firebase एडमिन पैनल बनाएं",
@@ -678,6 +680,17 @@ export const hi: FireCMSTranslations = {
678
680
  settings_appcheck_updated: "AppCheck अपडेट किया गया",
679
681
  settings_appcheck_error: "AppCheck अपडेट करने में त्रुटि",
680
682
 
683
+ // --- Permission Error View ---
684
+ missing_firestore_security_rules: "Firestore सुरक्षा नियम गायब हैं",
685
+ firecms_cloud_requires_security_rule: "FireCMS Cloud को आपके Firestore में प्रमाणित उपयोगकर्ताओं को एक्सेस देने के लिए एक विशिष्ट सुरक्षा नियम की आवश्यकता है। संग्रह",
686
+ cannot_be_accessed_without_it: "पर इसके बिना नहीं पहुंचा जा सकता।",
687
+ required_security_rule: "आवश्यक सुरक्षा नियम",
688
+ fix_automatically: "स्वचालित रूप से ठीक करें",
689
+ open_firebase_rules: "Firebase नियम खोलें",
690
+ security_rules_updated_successfully: "सुरक्षा नियम सफलतापूर्वक अपडेट किए गए! कृपया अपना डेटा लोड करने के लिए पेज को रीफ्रेश करें।",
691
+ sec_rules_fixing: "ठीक किया जा रहा है...",
692
+ sec_rules_fixed: "ठीक हो गया!",
693
+
681
694
  // ─── Text Search Dialog ─────────────────────────────────────
682
695
  text_search_dialog_title: "पाठ खोज सक्षम करें",
683
696
  text_search_local_not_recommended: "बड़ी संग्रहों के लिए स्थानीय पाठ खोज की अनुशंसा नहीं की जाती है।",
@@ -687,5 +700,19 @@ export const hi: FireCMSTranslations = {
687
700
  text_search_own_implementation: "आपने अपना स्वयं का पाठ खोज नियंत्रक लागू किया है। आप अपने संग्रह के लिए पाठ खोज सक्षम कर सकते हैं।",
688
701
  text_search_enable_for_collection: "इस संग्रह के लिए सक्षम करें",
689
702
  text_search_enable_for_project: "प्रोजेक्ट के लिए सक्षम करें",
690
- text_search_enabled_snackbar: "स्थानीय पाठ खोज सक्षम की गई"
703
+ text_search_enabled_snackbar: "स्थानीय पाठ खोज सक्षम की गई",
704
+
705
+ // ─── GCP Marketplace ─────────────────────────────────────────
706
+ marketplace_managed_by_gcp: "GCP Marketplace के माध्यम से प्रबंधित",
707
+ marketplace_billing_note: "आपकी सदस्यता Google Cloud Marketplace के माध्यम से प्रबंधित है। योजना परिवर्तन, बिलिंग और रद्दीकरण GCP कंसोल में संभाले जाते हैं।",
708
+ marketplace_manage_in_gcp_console: "GCP कंसोल में प्रबंधित करें",
709
+ marketplace_plan_changes_note: "अपनी योजना बदलने या रद्द करने के लिए, अपने GCP Marketplace ऑर्डर पर जाएं।",
710
+ marketplace_welcome_title: "GCP Marketplace से स्वागत है!",
711
+ marketplace_welcome_subtitle: "आपकी Google Cloud Marketplace सदस्यता सक्रिय है। इसे लिंक करने के लिए एक मौजूदा प्रोजेक्ट चुनें या एक नया बनाएं।",
712
+ marketplace_select_or_create_project: "प्रोजेक्ट चुनें या बनाएं",
713
+ marketplace_link_project: "प्रोजेक्ट लिंक करें",
714
+ marketplace_linking: "प्रोजेक्ट लिंक हो रहा है…",
715
+ marketplace_link_success: "प्रोजेक्ट सफलतापूर्वक लिंक हो गया! रीडायरेक्ट हो रहा है…",
716
+ marketplace_link_error: "प्रोजेक्ट लिंक करने में त्रुटि। कृपया पुनः प्रयास करें।",
717
+ marketplace_no_account_id: "कोई GCP Marketplace खाता ID नहीं मिली। कृपया GCP Marketplace से शुरू करें।",
691
718
  };
package/src/locales/it.ts CHANGED
@@ -437,6 +437,8 @@ export const it: FireCMSTranslations = {
437
437
  cms_users: "Utenti CMS",
438
438
  roles_menu: "Ruoli",
439
439
  project_settings: "Impostazioni del progetto",
440
+ firestore_explorer: "Esplora Firestore",
441
+ explore_your_firestore_data: "Esplora i tuoi dati Firestore",
440
442
 
441
443
  // ─── FireCMS Cloud Login ──────────────────────────────────────
442
444
  build_admin_panel_in_minutes: "Crea il tuo pannello di amministrazione Firebase in pochi minuti",
@@ -678,6 +680,17 @@ export const it: FireCMSTranslations = {
678
680
  settings_appcheck_updated: "AppCheck aggiornato",
679
681
  settings_appcheck_error: "Errore nell'aggiornamento di AppCheck",
680
682
 
683
+ // --- Permission Error View ---
684
+ missing_firestore_security_rules: "Regole di sicurezza Firestore mancanti",
685
+ firecms_cloud_requires_security_rule: "FireCMS Cloud richiede una regola di sicurezza specifica nel tuo Firestore per concedere l'accesso agli utenti autenticati. La collezione",
686
+ cannot_be_accessed_without_it: "non può essere visitata senza di essa.",
687
+ required_security_rule: "Regola di sicurezza richiesta",
688
+ fix_automatically: "Correggi automaticamente",
689
+ open_firebase_rules: "Apri le regole Firebase",
690
+ security_rules_updated_successfully: "Regole di sicurezza aggiornate con successo! Per favore aggiorna la pagina per caricare i tuoi dati.",
691
+ sec_rules_fixing: "Correzione...",
692
+ sec_rules_fixed: "Corretto!",
693
+
681
694
  // ─── Text Search Dialog ─────────────────────────────────────
682
695
  text_search_dialog_title: "Abilita ricerca testuale",
683
696
  text_search_local_not_recommended: "La ricerca testuale locale non è consigliata per collezioni di grandi dimensioni.",
@@ -687,5 +700,19 @@ export const it: FireCMSTranslations = {
687
700
  text_search_own_implementation: "Hai implementato il tuo controller di ricerca testuale. Puoi abilitare la ricerca testuale per la tua collezione.",
688
701
  text_search_enable_for_collection: "Abilita per questa collezione",
689
702
  text_search_enable_for_project: "Abilita per il progetto",
690
- text_search_enabled_snackbar: "Ricerca testuale locale abilitata"
703
+ text_search_enabled_snackbar: "Ricerca testuale locale abilitata",
704
+
705
+ // ─── GCP Marketplace ─────────────────────────────────────────
706
+ marketplace_managed_by_gcp: "Gestito tramite GCP Marketplace",
707
+ marketplace_billing_note: "Il tuo abbonamento è gestito tramite Google Cloud Marketplace. Le modifiche al piano, la fatturazione e la cancellazione vengono gestite nella console GCP.",
708
+ marketplace_manage_in_gcp_console: "Gestisci nella console GCP",
709
+ marketplace_plan_changes_note: "Per modificare il piano o annullare, visita i tuoi ordini GCP Marketplace.",
710
+ marketplace_welcome_title: "Benvenuto da GCP Marketplace!",
711
+ marketplace_welcome_subtitle: "Il tuo abbonamento Google Cloud Marketplace è attivo. Seleziona un progetto esistente o creane uno nuovo per collegarlo.",
712
+ marketplace_select_or_create_project: "Seleziona o crea un progetto",
713
+ marketplace_link_project: "Collega progetto",
714
+ marketplace_linking: "Collegamento del progetto in corso…",
715
+ marketplace_link_success: "Progetto collegato con successo! Reindirizzamento…",
716
+ marketplace_link_error: "Errore durante il collegamento del progetto. Riprova.",
717
+ marketplace_no_account_id: "Nessun ID account GCP Marketplace trovato. Inizia dal GCP Marketplace.",
691
718
  };
package/src/locales/pt.ts CHANGED
@@ -442,6 +442,8 @@ export const pt: FireCMSTranslations = {
442
442
  cms_users: "Utilizadores do CMS",
443
443
  roles_menu: "Funções",
444
444
  project_settings: "Definições do projeto",
445
+ firestore_explorer: "Explorador do Firestore",
446
+ explore_your_firestore_data: "Explore os seus dados do Firestore",
445
447
 
446
448
  // ─── FireCMS Cloud Login ──────────────────────────────────────
447
449
  build_admin_panel_in_minutes: "Construa o Seu Painel de Administração Firebase em Minutos",
@@ -687,6 +689,17 @@ export const pt: FireCMSTranslations = {
687
689
  settings_appcheck_updated: "AppCheck atualizado",
688
690
  settings_appcheck_error: "Erro ao atualizar o AppCheck",
689
691
 
692
+ // --- Permission Error View ---
693
+ missing_firestore_security_rules: "Regras de Segurança do Firestore Ausentes",
694
+ firecms_cloud_requires_security_rule: "O FireCMS Cloud requer uma regra de segurança específica no seu Firestore para conceder acesso a usuários autenticados. A coleção",
695
+ cannot_be_accessed_without_it: "não pode ser acessada sem ela.",
696
+ required_security_rule: "Regra de segurança obrigatória",
697
+ fix_automatically: "Corrigir automaticamente",
698
+ open_firebase_rules: "Abrir Regras do Firebase",
699
+ security_rules_updated_successfully: "Regras de segurança atualizadas com sucesso! Por favor atualize a página para carregar seus dados.",
700
+ sec_rules_fixing: "Corrigindo...",
701
+ sec_rules_fixed: "Corrigido!",
702
+
690
703
  // ─── Text Search Dialog ─────────────────────────────────────
691
704
  text_search_dialog_title: "Ativar pesquisa de texto",
692
705
  text_search_local_not_recommended: "A pesquisa de texto local não é recomendada para coleções grandes.",
@@ -696,5 +709,19 @@ export const pt: FireCMSTranslations = {
696
709
  text_search_own_implementation: "Implementou o seu próprio controlador de pesquisa de texto. Pode ativar a pesquisa de texto para a sua coleção.",
697
710
  text_search_enable_for_collection: "Ativar para esta coleção",
698
711
  text_search_enable_for_project: "Ativar para o projeto",
699
- text_search_enabled_snackbar: "Pesquisa de texto local ativada"
712
+ text_search_enabled_snackbar: "Pesquisa de texto local ativada",
713
+
714
+ // ─── GCP Marketplace ─────────────────────────────────────────
715
+ marketplace_managed_by_gcp: "Gerenciado via GCP Marketplace",
716
+ marketplace_billing_note: "Sua assinatura é gerenciada pelo Google Cloud Marketplace. Alterações de plano, faturamento e cancelamento são feitos no console do GCP.",
717
+ marketplace_manage_in_gcp_console: "Gerenciar no console do GCP",
718
+ marketplace_plan_changes_note: "Para alterar seu plano ou cancelar, visite seus pedidos do GCP Marketplace.",
719
+ marketplace_welcome_title: "Bem-vindo do GCP Marketplace!",
720
+ marketplace_welcome_subtitle: "Sua assinatura do Google Cloud Marketplace está ativa. Selecione um projeto existente ou crie um novo para vinculá-lo.",
721
+ marketplace_select_or_create_project: "Selecionar ou criar um projeto",
722
+ marketplace_link_project: "Vincular projeto",
723
+ marketplace_linking: "Vinculando projeto…",
724
+ marketplace_link_success: "Projeto vinculado com sucesso! Redirecionando…",
725
+ marketplace_link_error: "Erro ao vincular o projeto. Por favor, tente novamente.",
726
+ marketplace_no_account_id: "Nenhum ID de conta do GCP Marketplace encontrado. Por favor, comece pelo GCP Marketplace.",
700
727
  };
@@ -11,6 +11,7 @@ import {
11
11
  } from "../types";
12
12
 
13
13
  import { resolveProperty } from "../util";
14
+ import { jsonStringifyReplacer } from "../util/objects";
14
15
 
15
16
  import { PropertyPreviewProps } from "./PropertyPreviewProps";
16
17
  import { useAuthController, useCustomizationController } from "../hooks";
@@ -79,7 +80,9 @@ export const PropertyPreview = React.memo(function PropertyPreview<T extends CMS
79
80
  } else if (property.dataType === "string") {
80
81
  const stringProperty = property as ResolvedStringProperty;
81
82
  if (typeof value === "string") {
82
- if (stringProperty.storage) {
83
+ if (stringProperty.markdown) {
84
+ content = <Markdown source={value} size={"small"} />;
85
+ } else if (stringProperty.storage) {
83
86
  const filePath = stringProperty.storage.previewUrl ? stringProperty.storage.previewUrl(value) : value;
84
87
  content = <StorageThumbnail
85
88
  interactive={interactive}
@@ -100,8 +103,6 @@ export const PropertyPreview = React.memo(function PropertyPreview<T extends CMS
100
103
  interactive={interactive}
101
104
  fill={fill}
102
105
  previewType={stringProperty.url} />;
103
- } else if (stringProperty.markdown) {
104
- content = <Markdown source={value} size={"small"} />;
105
106
  } else if (stringProperty.userSelect) {
106
107
  content = <UserPreview
107
108
  value={value}
@@ -234,7 +235,7 @@ export const PropertyPreview = React.memo(function PropertyPreview<T extends CMS
234
235
  content = buildWrongValueType(propertyKey, property.dataType, value);
235
236
  }
236
237
  } else {
237
- content = JSON.stringify(value);
238
+ content = JSON.stringify(value, jsonStringifyReplacer);
238
239
  }
239
240
 
240
241
  return content === undefined || content === null || (Array.isArray(content) && content.length === 0)
@@ -246,6 +247,6 @@ function buildWrongValueType(name: string | undefined, dataType: string, value:
246
247
  console.warn(`Unexpected value for property ${name}, of type ${dataType}`, value);
247
248
  return (
248
249
  <ErrorView title={"Unexpected value"}
249
- error={`${JSON.stringify(value)}`} />
250
+ error={`${JSON.stringify(value, jsonStringifyReplacer)}`} />
250
251
  );
251
252
  }
@@ -6,6 +6,7 @@ import { PreviewSize } from "../PropertyPreviewProps";
6
6
  import { Skeleton } from "@firecms/ui";
7
7
  import { ErrorBoundary, ErrorView } from "../../components";
8
8
  import { EntityPreview, EntityPreviewContainer } from "../../components/EntityPreview";
9
+ import { jsonStringifyReplacer } from "../../util/objects";
9
10
 
10
11
  export type ReferencePreviewProps = {
11
12
  disabled?: boolean;
@@ -29,7 +30,7 @@ export const ReferencePreview = function ReferencePreview(props: ReferencePrevie
29
30
  onClick={props.onClick}
30
31
  size={props.size ?? "medium"}>
31
32
  <ErrorView error={"Unexpected value. Click to edit"}
32
- tooltip={JSON.stringify(reference)}/>
33
+ tooltip={JSON.stringify(reference, jsonStringifyReplacer)}/>
33
34
  </EntityPreviewContainer>;
34
35
  }
35
36
  return <ErrorBoundary>
@@ -6,6 +6,7 @@ import { PropertyPreview } from "../PropertyPreview";
6
6
  import { cls, defaultBorderMixin, Typography } from "@firecms/ui";
7
7
  import { ErrorBoundary } from "../../components";
8
8
  import { EmptyValue } from "../components/EmptyValue";
9
+ import { DatePreview } from "../components/DatePreview";
9
10
 
10
11
  /**
11
12
  * @group Preview components
@@ -111,37 +112,58 @@ export function KeyValuePreview({ value }: { value: any }) {
111
112
  return <div
112
113
  className="flex flex-col gap-1 w-full">
113
114
  {
114
- Object.entries(value).map(([key, childValue]: [string, any]) => (
115
- <div
116
- key={`map_preview_table_${key}}`}
117
- className={cls(defaultBorderMixin, "last:border-b-0 border-b")}>
115
+ Object.entries(value).map(([key, childValue]: [string, any]) => {
116
+ const isTimestampObj = childValue && typeof childValue === "object" && (
117
+ childValue instanceof Date ||
118
+ ("_seconds" in childValue && "_nanoseconds" in childValue && typeof childValue._seconds === "number" && typeof childValue._nanoseconds === "number") ||
119
+ ("seconds" in childValue && "nanoseconds" in childValue && typeof childValue.seconds === "number" && typeof childValue.nanoseconds === "number")
120
+ );
121
+
122
+ const isScalar = childValue && (typeof childValue !== "object" || isTimestampObj);
123
+
124
+ return (
118
125
  <div
119
- className={"flex flex-row pt-0.5 pb-0.5 gap-2"}>
120
- <div
121
- key={`table-cell-title-${key}-${key}`}
122
- className="min-w-[140px] w-[25%] py-1">
123
- <Typography variant={"caption"}
124
- className={"font-semibold break-words"}
125
- color={"secondary"}>
126
- {key}
127
- </Typography>
128
- </div>
126
+ key={`map_preview_table_${key}}`}
127
+ className={cls(defaultBorderMixin, "last:border-b-0 border-b")}>
129
128
  <div
130
- className="flex-grow max-w-[75%]">
131
- {childValue && typeof childValue !== "object" && <Typography>
132
- <ErrorBoundary>
133
- {childValue.toString()}
134
- </ErrorBoundary>
135
- </Typography>}
129
+ className={"flex flex-row pt-0.5 pb-0.5 gap-2"}>
130
+ <div
131
+ key={`table-cell-title-${key}-${key}`}
132
+ className="min-w-[140px] w-[25%] py-1">
133
+ <Typography variant={"caption"}
134
+ className={"font-semibold break-words"}
135
+ color={"secondary"}>
136
+ {key}
137
+ </Typography>
138
+ </div>
139
+ <div
140
+ className="flex-grow max-w-[75%]">
141
+ {isScalar && (isTimestampObj ? (
142
+ <ErrorBoundary>
143
+ <DatePreview date={
144
+ childValue instanceof Date ? childValue :
145
+ typeof childValue.toDate === "function" ? childValue.toDate() :
146
+ "_seconds" in childValue ? new Date(childValue._seconds * 1000 + childValue._nanoseconds / 1000000) :
147
+ new Date(childValue.seconds * 1000 + childValue.nanoseconds / 1000000)
148
+ } />
149
+ </ErrorBoundary>
150
+ ) : (
151
+ <Typography>
152
+ <ErrorBoundary>
153
+ {childValue.toString()}
154
+ </ErrorBoundary>
155
+ </Typography>
156
+ ))}
157
+ </div>
136
158
  </div>
159
+ {typeof childValue === "object" && !isTimestampObj &&
160
+ <div className={cls(defaultBorderMixin, "border-l pl-4")}>
161
+ <KeyValuePreview value={childValue}/>
162
+ </div>
163
+ }
137
164
  </div>
138
- {typeof childValue === "object" &&
139
- <div className={cls(defaultBorderMixin, "border-l pl-4")}>
140
- <KeyValuePreview value={childValue}/>
141
- </div>
142
- }
143
- </div>
144
- ))
165
+ );
166
+ })
145
167
  }
146
168
  </div>;
147
169
  }
@@ -1,7 +1,6 @@
1
1
  import { Blocker, useBlocker, useLocation } from "react-router";
2
- import { EntityEditView } from "../core/EntityEditView";
2
+ import React, { useEffect, useRef, useState } from "react";
3
3
  import { useNavigationController } from "../hooks";
4
- import { useEffect, useRef, useState } from "react";
5
4
  import { useNavigate } from "react-router-dom";
6
5
  import {
7
6
  getNavigationEntriesFromPath,
@@ -11,7 +10,11 @@ import {
11
10
  } from "../util/navigation_from_path";
12
11
  import { useBreadcrumbsController } from "../hooks/useBreadcrumbsController";
13
12
  import { toArray } from "../util/arrays";
14
- import { EntityCollectionView, NotFoundPage } from "../components";
13
+ import { NotFoundPage } from "../components";
14
+ import { lazyEager } from "../util/lazy_eager";
15
+
16
+ const EntityEditView = lazyEager<typeof import("../core/EntityEditView")["EntityEditView"]>(() => import("../core/EntityEditView"), "EntityEditView");
17
+ const EntityCollectionView = lazyEager<typeof import("../components/EntityCollectionView/EntityCollectionView")["EntityCollectionView"]>(() => import("../components/EntityCollectionView/EntityCollectionView"), "EntityCollectionView");
15
18
  import { UnsavedChangesDialog } from "../components/UnsavedChangesDialog";
16
19
  import { EntityCollection } from "../types";
17
20
 
@@ -88,15 +91,17 @@ export function FireCMSRoute() {
88
91
  collection = navigation.getCollection(navigationEntries[0].path);
89
92
  if (!collection)
90
93
  return null;
91
- return <EntityCollectionView
92
- key={`collection_view_${collection.id ?? collection.path}`}
93
- isSubCollection={false}
94
- parentCollectionIds={[]}
95
- fullPath={collection.path}
96
- fullIdPath={collection.id}
97
- updateUrl={true}
98
- {...collection}
99
- Actions={toArray(collection.Actions)} />
94
+ return <React.Suspense fallback={null}>
95
+ <EntityCollectionView
96
+ key={`collection_view_${collection.id ?? collection.path}`}
97
+ isSubCollection={false}
98
+ parentCollectionIds={[]}
99
+ fullPath={collection.path}
100
+ fullIdPath={collection.id}
101
+ updateUrl={true}
102
+ {...collection}
103
+ Actions={toArray(collection.Actions)} />
104
+ </React.Suspense>;
100
105
  }
101
106
 
102
107
  if (isSidePanel) {
@@ -109,15 +114,17 @@ export function FireCMSRoute() {
109
114
  collection = navigation.getCollection(firstEntry.path);
110
115
  if (!collection)
111
116
  return null;
112
- return <EntityCollectionView
113
- key={`collection_view_${collection.id ?? collection.path}`}
114
- fullIdPath={collection.id}
115
- isSubCollection={false}
116
- parentCollectionIds={[]}
117
- fullPath={collection.path}
118
- updateUrl={true}
119
- {...collection}
120
- Actions={toArray(collection.Actions)} />;
117
+ return <React.Suspense fallback={null}>
118
+ <EntityCollectionView
119
+ key={`collection_view_${collection.id ?? collection.path}`}
120
+ fullIdPath={collection.id}
121
+ isSubCollection={false}
122
+ parentCollectionIds={[]}
123
+ fullPath={collection.path}
124
+ updateUrl={true}
125
+ {...collection}
126
+ Actions={toArray(collection.Actions)} />
127
+ </React.Suspense>;
121
128
  }
122
129
  }
123
130
 
@@ -215,39 +222,41 @@ function EntityFullScreenRoute({
215
222
  const fullIdPath = isNew ? lastCollectionEntry!.path : lastEntityEntry!.path;
216
223
  const collectionPath = navigation.resolveIdsFrom(fullIdPath);
217
224
  return <>
218
- <EntityEditView
219
- key={collection.id + "_" + (isNew ? "new" : (isCopy ? entityId + "_copy" : entityId))}
220
- entityId={isNew ? undefined : entityId}
221
- fullIdPath={fullIdPath}
222
- collection={collection}
223
- layout={"full_screen"}
224
- path={collectionPath}
225
- copy={isCopy}
226
- selectedTab={selectedTab ?? undefined}
227
- onValuesModified={(modified) => blocked.current = modified}
228
- onSaved={(params) => {
229
- const newSelectedTab = params.selectedTab;
230
- const newEntityId = params.entityId;
231
- if (newSelectedTab) {
232
- navigate(`${basePath}/${newEntityId}/${newSelectedTab}`, { replace: true });
233
- } else {
234
- navigate(`${basePath}/${newEntityId}`, { replace: true });
235
- }
236
- }}
237
- onTabChange={(params) => {
238
- setSelectedTab(params.selectedTab);
239
- if (isNew) {
240
- return;
241
- }
242
- const newSelectedTab = params.selectedTab;
243
- if (newSelectedTab) {
244
- navigate(`${basePath}/${entityId}/${newSelectedTab}`, { replace: true });
245
- } else {
246
- navigate(`${basePath}/${entityId}`, { replace: true });
247
- }
248
- }}
249
- parentCollectionIds={parentCollectionIds}
250
- />
225
+ <React.Suspense fallback={null}>
226
+ <EntityEditView
227
+ key={collection.id + "_" + (isNew ? "new" : (isCopy ? entityId + "_copy" : entityId))}
228
+ entityId={isNew ? undefined : entityId}
229
+ fullIdPath={fullIdPath}
230
+ collection={collection}
231
+ layout={"full_screen"}
232
+ path={collectionPath}
233
+ copy={isCopy}
234
+ selectedTab={selectedTab ?? undefined}
235
+ onValuesModified={(modified) => blocked.current = modified}
236
+ onSaved={(params) => {
237
+ const newSelectedTab = params.selectedTab;
238
+ const newEntityId = params.entityId;
239
+ if (newSelectedTab) {
240
+ navigate(`${basePath}/${newEntityId}/${newSelectedTab}`, { replace: true });
241
+ } else {
242
+ navigate(`${basePath}/${newEntityId}`, { replace: true });
243
+ }
244
+ }}
245
+ onTabChange={(params) => {
246
+ setSelectedTab(params.selectedTab);
247
+ if (isNew) {
248
+ return;
249
+ }
250
+ const newSelectedTab = params.selectedTab;
251
+ if (newSelectedTab) {
252
+ navigate(`${basePath}/${entityId}/${newSelectedTab}`, { replace: true });
253
+ } else {
254
+ navigate(`${basePath}/${entityId}`, { replace: true });
255
+ }
256
+ }}
257
+ parentCollectionIds={parentCollectionIds}
258
+ />
259
+ </React.Suspense>
251
260
 
252
261
  <UnsavedChangesDialog
253
262
  open={blocker?.state === "blocked"}
@@ -163,6 +163,31 @@ export interface EntityCollection<M extends Record<string, any> = any, USER exte
163
163
  */
164
164
  subcollections?: EntityCollection<any, any>[];
165
165
 
166
+ /**
167
+ * You can group subcollections and custom views into dropdown menus
168
+ * in the entity view tabs. Views listed in a group will be removed
169
+ * from the top-level tabs and shown under a single dropdown instead.
170
+ *
171
+ * @example
172
+ * ```tsx
173
+ * const productsCollection = buildCollection({
174
+ * id: "products",
175
+ * path: "products",
176
+ * name: "Products",
177
+ * properties: { ... },
178
+ * subcollections: [localesCollection, reviewsCollection],
179
+ * entityViews: [sampleView],
180
+ * viewGroups: [
181
+ * {
182
+ * name: "Related data",
183
+ * views: ["locales", "reviews", "sample_view"]
184
+ * }
185
+ * ]
186
+ * });
187
+ * ```
188
+ */
189
+ viewGroups?: ViewGroup[];
190
+
166
191
  /**
167
192
  * This interface defines all the callbacks that can be used when an entity
168
193
  * is being created, updated or deleted.
@@ -413,6 +438,21 @@ export interface KanbanConfig<M extends Record<string, any> = any> {
413
438
  columnProperty: Extract<keyof M, string>;
414
439
  }
415
440
 
441
+ /**
442
+ * You can group subcollections and custom views into dropdown menus in the entity view tabs.
443
+ * @group Collections
444
+ */
445
+ export interface ViewGroup {
446
+ /**
447
+ * Name of the group
448
+ */
449
+ name: string;
450
+ /**
451
+ * Array of subcollection paths/ids or custom view keys
452
+ */
453
+ views: string[];
454
+ }
455
+
416
456
  /**
417
457
  * View mode for displaying a collection.
418
458
  * @group Collections
@@ -180,6 +180,17 @@ export interface BaseProperty<T extends CMSType, CustomProps = any> {
180
180
  * @see https://jsonlogic.com/ for JSON Logic syntax
181
181
  */
182
182
  conditions?: PropertyConditions;
183
+
184
+ /**
185
+ * Set this property to true to provide the UX to explicitly set the value to `null`.
186
+ * Defaults to `false`.
187
+ */
188
+ nullable?: boolean;
189
+
190
+ /**
191
+ * @deprecated Use `nullable` instead.
192
+ */
193
+ clearable?: boolean;
183
194
  }
184
195
 
185
196
  /**
@@ -620,11 +631,6 @@ export interface NumberProperty extends BaseProperty<number> {
620
631
  * Rules for validating this property
621
632
  */
622
633
  validation?: NumberPropertyValidationSchema,
623
-
624
- /**
625
- * Add an icon to clear the value and set it to `null`. Defaults to `false`
626
- */
627
- clearable?: boolean;
628
634
  }
629
635
 
630
636
  /**
@@ -735,11 +741,6 @@ export interface StringProperty extends BaseProperty<string> {
735
741
  */
736
742
  validation?: StringPropertyValidationSchema;
737
743
 
738
- /**
739
- * Add an icon to clear the value and set it to `null`. Defaults to `false`
740
- */
741
- clearable?: boolean;
742
-
743
744
  /**
744
745
  * You can use this property (a string) to behave as a reference to another
745
746
  * collection. The stored value is the ID of the entity in the
@@ -467,6 +467,8 @@ export interface FireCMSTranslations {
467
467
  cms_users: string;
468
468
  roles_menu: string;
469
469
  project_settings: string;
470
+ firestore_explorer: string;
471
+ explore_your_firestore_data: string;
470
472
 
471
473
  // ─── FireCMS Cloud Login ──────────────────────────────────────
472
474
  build_admin_panel_in_minutes: string;
@@ -722,4 +724,29 @@ export interface FireCMSTranslations {
722
724
  settings_appcheck_refresh_note: string;
723
725
  settings_appcheck_updated: string;
724
726
  settings_appcheck_error: string;
727
+
728
+ // --- Permission Error View ---
729
+ missing_firestore_security_rules: string;
730
+ firecms_cloud_requires_security_rule: string;
731
+ cannot_be_accessed_without_it: string;
732
+ required_security_rule: string;
733
+ fix_automatically: string;
734
+ open_firebase_rules: string;
735
+ security_rules_updated_successfully: string;
736
+ sec_rules_fixing: string;
737
+ sec_rules_fixed: string;
738
+
739
+ // ─── GCP Marketplace ─────────────────────────────────────────
740
+ marketplace_managed_by_gcp: string;
741
+ marketplace_billing_note: string;
742
+ marketplace_manage_in_gcp_console: string;
743
+ marketplace_plan_changes_note: string;
744
+ marketplace_welcome_title: string;
745
+ marketplace_welcome_subtitle: string;
746
+ marketplace_select_or_create_project: string;
747
+ marketplace_link_project: string;
748
+ marketplace_linking: string;
749
+ marketplace_link_success: string;
750
+ marketplace_link_error: string;
751
+ marketplace_no_account_id: string;
725
752
  }