import { useUserSession } from '@vertesia/ui/session'; import { useState, useRef, useEffect } from 'react'; import { useUITranslation } from '../../../../i18n/index.js'; import { Button, Modal, ModalBody, ModalFooter, ModalTitle, useToast, useTheme } from '@vertesia/ui/core'; import { ContentObject } from '@vertesia/common'; import { useNavigate } from "@vertesia/ui/router"; // Import Monaco Editor wrapper import { MonacoEditor, IEditorApi } from '@vertesia/ui/widgets'; // Import SaveVersionConfirmModal import { SaveVersionConfirmModal } from './SaveVersionConfirmModal'; export interface PropertiesEditorModalProps { isOpen: boolean; onClose: () => void; object: ContentObject; refetch?: () => Promise; } export function PropertiesEditorModal({ isOpen, onClose, object, refetch }: PropertiesEditorModalProps) { const { client, store } = useUserSession(); const toast = useToast(); const { t } = useUITranslation(); const { theme } = useTheme(); const navigate = useNavigate(); const [isLoading, setIsLoading] = useState(false); const [propertiesJson, setPropertiesJson] = useState(''); const [showConfirmation, setShowConfirmation] = useState(false); const [parsedProperties, setParsedProperties] = useState(null); const editorRef = useRef(undefined); const [jsonSchema, setJsonSchema] = useState(null); //TODO state not used const [_newVersionId, setNewVersionId] = useState(null); // Initialize editor content when modal opens useEffect(() => { if (isOpen) { setPropertiesJson(JSON.stringify(object.properties || {}, null, 2)); // Try to fetch JSON schema if object has a type if (object.type?.id) { fetchJsonSchema(object.type.id); } } }, [isOpen, object]); // Fetch JSON schema for the object type async function fetchJsonSchema(typeId: string) { try { const typeDetails = await store.types.retrieve(typeId); if (typeDetails.object_schema) { setJsonSchema(typeDetails.object_schema); } } catch (error) { console.error('Failed to fetch JSON schema:', error); } } // Configure Monaco editor with JSON schema validation const beforeMount = (monaco: typeof import('monaco-editor')) => { if (jsonSchema) { monaco.languages.json.jsonDefaults.setDiagnosticsOptions({ validate: true, schemas: [ { uri: 'http://myserver/object-schema.json', fileMatch: ['*'], schema: jsonSchema } ] }); } }; // Validate JSON and open confirmation modal function handleSave() { if (!editorRef.current) return; const editorValue = editorRef.current.getValue(); try { const properties = JSON.parse(editorValue); setParsedProperties(properties); setShowConfirmation(true); } catch (err) { toast({ status: 'error', title: t('store.invalidJson'), description: t('store.pleaseFixJsonSyntax'), duration: 5000 }); } } // Handle editor changes const handleEditorChange = (value: string) => { setPropertiesJson(value); }; // Save properties async function saveProperties(createVersion: boolean, versionLabel?: string) { try { setIsLoading(true); const properties = parsedProperties || JSON.parse(propertiesJson); if (createVersion) { // Create a new version with the updated properties const response = await client.objects.update(object.id, { properties: properties }, { createRevision: true, revisionLabel: versionLabel }); // Store the new version ID for navigation if (response.id !== object.id) { setNewVersionId(response.id); } toast({ status: 'success', title: t('store.newVersionCreated'), description: t('store.newVersionCreatedDesc'), duration: 2000 }); // Close modals setShowConfirmation(false); onClose(); // Navigate to the new version if (response.id !== object.id) { // Delay slightly to allow modal closing to complete setTimeout(() => { navigate(`/objects/${response.id}`); toast({ status: 'info', title: t('store.viewingNewVersion'), description: versionLabel ? t('store.viewingVersionLabel', { label: versionLabel }) : t('store.viewingNewVersionDefault'), duration: 3000 }); }, 100); } } else { // Update the object properties in place await store.objects.update(object.id, { properties: properties }); toast({ status: 'success', title: t('store.propertiesUpdated'), description: t('store.propertiesUpdatedDesc'), duration: 2000 }); if (refetch) { await refetch(); } setShowConfirmation(false); onClose(); } } catch (error: any) { toast({ status: 'error', title: t('store.errorUpdatingProperties'), description: error.message || t('store.errorUpdatingPropertiesDefault'), duration: 5000 }); setIsLoading(false); } } // Handle closing the confirmation modal without saving function handleCancelConfirmation() { setShowConfirmation(false); } return ( <> {t('store.editProperties')}
{object.type?.name ? ( Editing properties for object type: {object.type.name} ) : ( {t('store.editingGenericDocument')} )} {jsonSchema && ( (JSON schema validation enabled) )}
handleEditorChange(update.state.doc.toString())} beforeMount={beforeMount} theme={theme === 'dark' ? 'vs-dark' : 'vs'} />
{/* Version Confirmation Modal */} ); }