@firecms/collection_editor 3.3.0 → 3.4.0-canary.2575a08

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.
@@ -1,6 +1,5 @@
1
1
  import React from "react";
2
- export declare function StoragePropertyField({ multiple, existing, disabled }: {
2
+ export declare function StoragePropertyField({ multiple, disabled }: {
3
3
  multiple: boolean;
4
- existing: boolean;
5
4
  disabled: boolean;
6
5
  }): React.JSX.Element;
package/package.json CHANGED
@@ -1,18 +1,19 @@
1
1
  {
2
2
  "name": "@firecms/collection_editor",
3
3
  "type": "module",
4
- "version": "3.3.0",
4
+ "version": "3.4.0-canary.2575a08",
5
5
  "main": "./dist/index.umd.js",
6
6
  "module": "./dist/index.es.js",
7
7
  "types": "./dist/index.d.ts",
8
8
  "source": "src/index.ts",
9
9
  "dependencies": {
10
- "@firecms/data_export": "^3.3.0",
11
- "@firecms/data_import": "^3.3.0",
12
- "@firecms/data_import_export": "^3.3.0",
13
- "@firecms/formex": "^3.3.0",
14
- "@firecms/schema_inference": "^3.3.0",
15
- "@firecms/ui": "^3.3.0",
10
+ "@firecms/core": "3.4.0-canary.2575a08",
11
+ "@firecms/data_export": "3.4.0-canary.2575a08",
12
+ "@firecms/data_import": "3.4.0-canary.2575a08",
13
+ "@firecms/data_import_export": "3.4.0-canary.2575a08",
14
+ "@firecms/formex": "3.4.0-canary.2575a08",
15
+ "@firecms/schema_inference": "3.4.0-canary.2575a08",
16
+ "@firecms/ui": "3.4.0-canary.2575a08",
16
17
  "json5": "^2.2.3",
17
18
  "prism-react-renderer": "^2.4.1"
18
19
  },
package/src/locales/de.ts CHANGED
@@ -19,9 +19,9 @@ export const collectionEditorTranslationsDe = {
19
19
  storage_placeholder_path: "{path} - Pfad dieser Entität",
20
20
  storage_placeholder_rand: "{rand} - Zufallswert zur Vermeidung von Namenskollisionen",
21
21
  include_bucket_url: "Bucket-URL (gs://...) im gespeicherten Wert einschließen",
22
- include_bucket_url_description: "Aktivieren Sie diese Einstellung, wenn Sie eine vollqualifizierte Speicher-URL (z. B. gs://mein-bucket/pfad/zur/datei) statt nur des Speicherpfads speichern möchten. Diese Einstellung kann nur bei der Erstellung geändert werden.",
22
+ include_bucket_url_description: "Aktivieren Sie diese Einstellung, wenn Sie eine vollqualifizierte Speicher-URL (z. B. gs://mein-bucket/pfad/zur/datei) statt nur des Speicherpfads speichern möchten. Eine Änderung wirkt sich nur auf neue Uploads aus: Bereits gespeicherte Werte behalten ihr aktuelles Format.",
23
23
  save_url_instead_of_path: "URL statt Speicherpfad speichern",
24
- save_url_description: "Aktivieren Sie diese Einstellung, wenn Sie bevorzugen, die Download-URL der hochgeladenen Datei statt des Speicherpfads zu speichern. Diese Einstellung kann nur bei der Erstellung geändert werden.",
24
+ save_url_description: "Aktivieren Sie diese Einstellung, wenn Sie bevorzugen, die Download-URL der hochgeladenen Datei statt des Speicherpfads zu speichern. Eine Änderung wirkt sich nur auf neue Uploads aus: Bereits gespeicherte Werte behalten ihr aktuelles Format.",
25
25
  max_size_bytes: "Maximale Größe (in Bytes)",
26
26
  image_resize_configuration: "Bildgrößenanpassungs-Konfiguration",
27
27
  image_resize_description: "Bilder vor dem Hochladen automatisch anpassen und optimieren (nur JPEG, PNG, WebP)",
package/src/locales/en.ts CHANGED
@@ -20,9 +20,9 @@ export const collectionEditorTranslationsEn = {
20
20
  storage_placeholder_path: "{path} - Path of this entity",
21
21
  storage_placeholder_rand: "{rand} - Random value used to avoid name collisions",
22
22
  include_bucket_url: "Include bucket URL (gs://...) in saved value",
23
- include_bucket_url_description: "Turn this setting on if you want to save a fully-qualified storage URL (e.g. gs://my-bucket/path/to/file) instead of just the storage path. You can only change this prop upon creation.",
23
+ include_bucket_url_description: "Turn this setting on if you want to save a fully-qualified storage URL (e.g. gs://my-bucket/path/to/file) instead of just the storage path. Changing it only affects new uploads: values already saved keep their current format.",
24
24
  save_url_instead_of_path: "Save URL instead of storage path",
25
- save_url_description: "Turn this setting on, if you prefer to save the download URL of the uploaded file instead of the storage path. You can only change this prop upon creation.",
25
+ save_url_description: "Turn this setting on, if you prefer to save the download URL of the uploaded file instead of the storage path. Changing it only affects new uploads: values already saved keep their current format.",
26
26
  max_size_bytes: "Max size (in bytes)",
27
27
  image_resize_configuration: "Image Resize Configuration",
28
28
  image_resize_description: "Automatically resize and optimize images before upload (JPEG, PNG, WebP only)",
package/src/locales/es.ts CHANGED
@@ -19,9 +19,9 @@ export const collectionEditorTranslationsEs = {
19
19
  storage_placeholder_path: "{path} - Ruta de esta entidad",
20
20
  storage_placeholder_rand: "{rand} - Valor aleatorio para evitar colisiones de nombres",
21
21
  include_bucket_url: "Incluir URL del bucket (gs://...) en el valor guardado",
22
- include_bucket_url_description: "Activa esta opción si deseas guardar una URL de almacenamiento completa (ej. gs://mi-bucket/ruta/al/archivo) en lugar de solo la ruta de almacenamiento. Solo puedes cambiar esta opción al crear.",
22
+ include_bucket_url_description: "Activa esta opción si deseas guardar una URL de almacenamiento completa (ej. gs://mi-bucket/ruta/al/archivo) en lugar de solo la ruta de almacenamiento. Cambiarla solo afecta a las nuevas subidas: los valores ya guardados mantienen su formato actual.",
23
23
  save_url_instead_of_path: "Guardar URL en lugar de ruta de almacenamiento",
24
- save_url_description: "Activa esta opción si prefieres guardar la URL de descarga del archivo subido en lugar de la ruta de almacenamiento. Solo puedes cambiar esta opción al crear.",
24
+ save_url_description: "Activa esta opción si prefieres guardar la URL de descarga del archivo subido en lugar de la ruta de almacenamiento. Cambiarla solo afecta a las nuevas subidas: los valores ya guardados mantienen su formato actual.",
25
25
  max_size_bytes: "Tamaño máximo (en bytes)",
26
26
  image_resize_configuration: "Configuración de redimensionamiento de imagen",
27
27
  image_resize_description: "Redimensionar y optimizar imágenes automáticamente antes de subirlas (solo JPEG, PNG, WebP)",
package/src/locales/fr.ts CHANGED
@@ -19,9 +19,9 @@ export const collectionEditorTranslationsFr = {
19
19
  storage_placeholder_path: "{path} - Chemin de cette entité",
20
20
  storage_placeholder_rand: "{rand} - Valeur aléatoire pour éviter les conflits de noms",
21
21
  include_bucket_url: "Inclure l'URL du bucket (gs://...) dans la valeur enregistrée",
22
- include_bucket_url_description: "Activez ce paramètre si vous souhaitez enregistrer une URL de stockage complète (ex. gs://mon-bucket/chemin/vers/fichier) au lieu du simple chemin de stockage. Vous ne pouvez modifier ce paramètre qu'à la création.",
22
+ include_bucket_url_description: "Activez ce paramètre si vous souhaitez enregistrer une URL de stockage complète (ex. gs://mon-bucket/chemin/vers/fichier) au lieu du simple chemin de stockage. Sa modification n'affecte que les nouveaux envois : les valeurs déjà enregistrées conservent leur format actuel.",
23
23
  save_url_instead_of_path: "Enregistrer l'URL au lieu du chemin de stockage",
24
- save_url_description: "Activez ce paramètre si vous préférez enregistrer l'URL de téléchargement du fichier plutôt que le chemin de stockage. Vous ne pouvez modifier ce paramètre qu'à la création.",
24
+ save_url_description: "Activez ce paramètre si vous préférez enregistrer l'URL de téléchargement du fichier plutôt que le chemin de stockage. Sa modification n'affecte que les nouveaux envois : les valeurs déjà enregistrées conservent leur format actuel.",
25
25
  max_size_bytes: "Taille maximale (en octets)",
26
26
  image_resize_configuration: "Configuration du redimensionnement d'image",
27
27
  image_resize_description: "Redimensionner et optimiser automatiquement les images avant le téléchargement (JPEG, PNG, WebP uniquement)",
package/src/locales/hi.ts CHANGED
@@ -19,9 +19,9 @@ export const collectionEditorTranslationsHi = {
19
19
  storage_placeholder_path: "{path} - इस इकाई का पथ",
20
20
  storage_placeholder_rand: "{rand} - नाम टकराव से बचने के लिए यादृच्छिक मूल्य",
21
21
  include_bucket_url: "सहेजे गए मान में बकेट URL (gs://...) शामिल करें",
22
- include_bucket_url_description: "यदि आप केवल स्टोरेज पथ के बजाय पूरी तरह से योग्य स्टोरेज URL (जैसे gs://my-bucket/path/to/file) सहेजना चाहते हैं तो इस सेटिंग को चालू करें। आप इसे केवल निर्माण के समय बदल सकते हैं।",
22
+ include_bucket_url_description: "यदि आप केवल स्टोरेज पथ के बजाय पूरी तरह से योग्य स्टोरेज URL (जैसे gs://my-bucket/path/to/file) सहेजना चाहते हैं तो इस सेटिंग को चालू करें। इसे बदलने का असर केवल नए अपलोड पर होता है: पहले से सहेजे गए मान अपने मौजूदा प्रारूप में बने रहते हैं।",
23
23
  save_url_instead_of_path: "स्टोरेज पथ के बजाय URL सहेजें",
24
- save_url_description: "यदि आप स्टोरेज पथ के बजाय अपलोड की गई फ़ाइल का डाउनलोड URL सहेजना पसंद करते हैं तो इस सेटिंग को चालू करें। आप इसे केवल निर्माण के समय बदल सकते हैं।",
24
+ save_url_description: "यदि आप स्टोरेज पथ के बजाय अपलोड की गई फ़ाइल का डाउनलोड URL सहेजना पसंद करते हैं तो इस सेटिंग को चालू करें। इसे बदलने का असर केवल नए अपलोड पर होता है: पहले से सहेजे गए मान अपने मौजूदा प्रारूप में बने रहते हैं।",
25
25
  max_size_bytes: "अधिकतम आकार (बाइट में)",
26
26
  image_resize_configuration: "छवि आकार बदलने का कॉन्फ़िगरेशन",
27
27
  image_resize_description: "अपलोड से पहले स्वचालित रूप से छवियों का आकार बदलें और अनुकूलित करें (केवल JPEG, PNG, WebP)",
package/src/locales/it.ts CHANGED
@@ -19,9 +19,9 @@ export const collectionEditorTranslationsIt = {
19
19
  storage_placeholder_path: "{path} - Percorso di questa entità",
20
20
  storage_placeholder_rand: "{rand} - Valore casuale per evitare conflitti di nomi",
21
21
  include_bucket_url: "Includi URL del bucket (gs://...) nel valore salvato",
22
- include_bucket_url_description: "Attiva questa impostazione se desideri salvare un URL di archiviazione completo (es. gs://mio-bucket/percorso/al/file) invece del solo percorso di archiviazione. Puoi modificare questa impostazione solo alla creazione.",
22
+ include_bucket_url_description: "Attiva questa impostazione se desideri salvare un URL di archiviazione completo (es. gs://mio-bucket/percorso/al/file) invece del solo percorso di archiviazione. La modifica influisce solo sui nuovi caricamenti: i valori già salvati mantengono il loro formato attuale.",
23
23
  save_url_instead_of_path: "Salva URL invece del percorso di archiviazione",
24
- save_url_description: "Attiva questa impostazione se preferisci salvare l'URL di download del file caricato invece del percorso di archiviazione. Puoi modificare questa impostazione solo alla creazione.",
24
+ save_url_description: "Attiva questa impostazione se preferisci salvare l'URL di download del file caricato invece del percorso di archiviazione. La modifica influisce solo sui nuovi caricamenti: i valori già salvati mantengono il loro formato attuale.",
25
25
  max_size_bytes: "Dimensione massima (in byte)",
26
26
  image_resize_configuration: "Configurazione ridimensionamento immagine",
27
27
  image_resize_description: "Ridimensiona e ottimizza automaticamente le immagini prima del caricamento (solo JPEG, PNG, WebP)",
package/src/locales/pt.ts CHANGED
@@ -19,9 +19,9 @@ export const collectionEditorTranslationsPt = {
19
19
  storage_placeholder_path: "{path} - Caminho desta entidade",
20
20
  storage_placeholder_rand: "{rand} - Valor aleatório para evitar colisões de nomes",
21
21
  include_bucket_url: "Incluir URL do bucket (gs://...) no valor salvo",
22
- include_bucket_url_description: "Ative esta configuração se deseja salvar uma URL de armazenamento completa (ex. gs://meu-bucket/caminho/para/arquivo) em vez de apenas o caminho de armazenamento. Você pode alterar esta configuração na criação.",
22
+ include_bucket_url_description: "Ative esta configuração se deseja salvar uma URL de armazenamento completa (ex. gs://meu-bucket/caminho/para/arquivo) em vez de apenas o caminho de armazenamento. Alterá-la afeta apenas os novos envios: os valores já salvos mantêm o formato atual.",
23
23
  save_url_instead_of_path: "Salvar URL em vez do caminho de armazenamento",
24
- save_url_description: "Ative esta configuração se preferir salvar a URL de download do arquivo enviado em vez do caminho de armazenamento. Você pode alterar esta configuração na criação.",
24
+ save_url_description: "Ative esta configuração se preferir salvar a URL de download do arquivo enviado em vez do caminho de armazenamento. Alterá-la afeta apenas os novos envios: os valores já salvos mantêm o formato atual.",
25
25
  max_size_bytes: "Tamanho máximo (em bytes)",
26
26
  image_resize_configuration: "Configuração de redimensionamento de imagem",
27
27
  image_resize_description: "Redimensionar e otimizar imagens automaticamente antes do upload (apenas JPEG, PNG, WebP)",
@@ -503,7 +503,7 @@ export function CollectionPropertiesEditorForm({
503
503
  !isPropertyBuilder(selectedProperty) &&
504
504
  <PropertyForm
505
505
  inArray={false}
506
- key={`edit_view_${selectedPropertyIndex}_${generationCounter}`}
506
+ key={`edit_view_${selectedPropertyFullId}_${generationCounter}`}
507
507
  existingProperty={!isNewCollection}
508
508
  autoUpdateId={false}
509
509
  allowDataInference={!isNewCollection}
@@ -547,7 +547,7 @@ export function CollectionPropertiesEditorForm({
547
547
  {asDialog && <PropertyFormDialog
548
548
  inArray={false}
549
549
  open={selectedPropertyIndex !== undefined}
550
- key={`edit_view_${selectedPropertyIndex}_${generationCounter}`}
550
+ key={`edit_view_${selectedPropertyFullId}_${generationCounter}`}
551
551
  autoUpdateId={!selectedProperty}
552
552
  allowDataInference={!isNewCollection}
553
553
  existingProperty={true}
@@ -72,6 +72,34 @@ export function DisplaySettingsForm({
72
72
  return result;
73
73
  }, [resolvedCollection.properties]);
74
74
 
75
+ // Get image properties (for imageProperty), used as the thumbnail in Cards/Kanban views
76
+ const imageProperties = useMemo(() => {
77
+ const result: { key: string; label: string; property: Property; }[] = [];
78
+ if (!resolvedCollection.properties) return result;
79
+
80
+ const isImageProperty = (prop: any): boolean => {
81
+ if (!prop || !("dataType" in prop)) return false;
82
+ if (prop.dataType === "string") {
83
+ return Boolean(prop.storage?.acceptedFiles?.includes("image/*")) || prop.url === "image";
84
+ }
85
+ if (prop.dataType === "array" && prop.of) {
86
+ return isImageProperty(prop.of);
87
+ }
88
+ return false;
89
+ };
90
+
91
+ Object.entries(resolvedCollection.properties).forEach(([key, prop]) => {
92
+ if (isImageProperty(prop)) {
93
+ result.push({
94
+ key,
95
+ label: (prop as Property).name || key,
96
+ property: prop as Property
97
+ });
98
+ }
99
+ });
100
+ return result;
101
+ }, [resolvedCollection.properties]);
102
+
75
103
  const showErrors = submitCount > 0;
76
104
 
77
105
  // Document ID generation value
@@ -246,6 +274,83 @@ export function DisplaySettingsForm({
246
274
  })()}
247
275
  </div>
248
276
 
277
+ {/* Image Property (used as thumbnail in Cards/Kanban views) */}
278
+ <div className={"col-span-12 mt-4"}>
279
+ {(() => {
280
+ const imagePropertyMissing = Boolean(values.imageProperty) &&
281
+ !imageProperties.some(p => p.key === values.imageProperty);
282
+
283
+ return (
284
+ <>
285
+ <Typography variant={"label"} color={"secondary"} className={"ml-3.5"}>{t("image_property")}</Typography>
286
+ <Select
287
+ key={`image-select-${imageProperties.length}`}
288
+ name="imageProperty"
289
+ size={"large"}
290
+ fullWidth={true}
291
+ position={"item-aligned"}
292
+ disabled={imageProperties.length === 0}
293
+ error={imagePropertyMissing}
294
+ value={(values.imageProperty as string) ?? ""}
295
+ onValueChange={(v) => {
296
+ setFieldValue("imageProperty", v || undefined);
297
+ }}
298
+ renderValue={(value) => {
299
+ if (imagePropertyMissing) {
300
+ return <span className="text-red-500">{value} ({t("not_found_suffix")})</span>;
301
+ }
302
+ const prop = imageProperties.find(p => p.key === value);
303
+ if (!prop) return t("select_a_property");
304
+ const fieldConfig = getFieldConfig(prop.property, customizationController.propertyConfigs);
305
+ return (
306
+ <div className="flex items-center gap-2">
307
+ <PropertyConfigBadge propertyConfig={fieldConfig} />
308
+ <span>{prop.label}</span>
309
+ </div>
310
+ );
311
+ }}
312
+ endAdornment={values.imageProperty ? (
313
+ <IconButton
314
+ size="small"
315
+ onClick={(e) => {
316
+ e.stopPropagation();
317
+ setFieldValue("imageProperty", undefined);
318
+ }}
319
+ >
320
+ <CloseIcon size="small" />
321
+ </IconButton>
322
+ ) : undefined}
323
+ >
324
+ {imageProperties.map((prop) => {
325
+ const fieldConfig = getFieldConfig(prop.property, customizationController.propertyConfigs);
326
+ return (
327
+ <SelectItem key={prop.key} value={prop.key}>
328
+ <div className="flex items-center gap-3">
329
+ <PropertyConfigBadge propertyConfig={fieldConfig} />
330
+ <div>
331
+ <div>{prop.label}</div>
332
+ <Typography variant="caption" color="secondary">
333
+ {fieldConfig?.name || prop.label}
334
+ </Typography>
335
+ </div>
336
+ </div>
337
+ </SelectItem>
338
+ );
339
+ })}
340
+ </Select>
341
+ <FieldCaption error={imagePropertyMissing}>
342
+ {imagePropertyMissing
343
+ ? t("image_property_not_found", { property: values.imageProperty as string ?? "" })
344
+ : imageProperties.length === 0
345
+ ? t("no_image_properties")
346
+ : t("image_property_description")
347
+ }
348
+ </FieldCaption>
349
+ </>
350
+ );
351
+ })()}
352
+ </div>
353
+
249
354
  {/* Default row size */}
250
355
  <div className={"col-span-12"}>
251
356
  <Select
@@ -498,13 +498,11 @@ function PropertyEditFormFields({
498
498
  showErrors={showErrors} />;
499
499
  } else if (selectedFieldConfigId === "file_upload") {
500
500
  childComponent =
501
- <StoragePropertyField existing={existing}
502
- multiple={false}
501
+ <StoragePropertyField multiple={false}
503
502
  disabled={disabled} />;
504
503
  } else if (selectedFieldConfigId === "multi_file_upload") {
505
504
  childComponent =
506
- <StoragePropertyField existing={existing}
507
- multiple={true}
505
+ <StoragePropertyField multiple={true}
508
506
  disabled={disabled} />;
509
507
  } else if (selectedFieldConfigId === "switch") {
510
508
  childComponent = <BooleanPropertyField disabled={disabled} />;
@@ -20,11 +20,9 @@ import { useTranslation } from "@firecms/core";
20
20
 
21
21
  export function StoragePropertyField({
22
22
  multiple,
23
- existing,
24
23
  disabled
25
24
  }: {
26
25
  multiple: boolean;
27
- existing: boolean;
28
26
  disabled: boolean;
29
27
  }) {
30
28
 
@@ -179,7 +177,7 @@ export function StoragePropertyField({
179
177
  }: FormexFieldProps) => {
180
178
  return <SwitchControl
181
179
  label={t("include_bucket_url")}
182
- disabled={existing || disabled}
180
+ disabled={disabled}
183
181
  form={form}
184
182
  field={field}/>;
185
183
  }}
@@ -197,7 +195,7 @@ export function StoragePropertyField({
197
195
  }: FormexFieldProps) => {
198
196
  return <SwitchControl
199
197
  label={t("save_url_instead_of_path")}
200
- disabled={existing || disabled}
198
+ disabled={disabled}
201
199
  form={form}
202
200
  field={field}/>;
203
201
  }}