import React, { useEffect, useState } from 'react'; import AlertDialog from '@/_ui/AlertDialog'; import { Alert } from '@/_ui/Alert'; import { toast } from 'react-hot-toast'; import { useTranslation } from 'react-i18next'; import Select from '@/_ui/Select'; import { shallow } from 'zustand/shallow'; import useStore from '@/AppBuilder/_stores/store'; import { useModuleContext } from '@/AppBuilder/_contexts/ModuleContext'; import { ButtonSolid } from '@/_ui/AppButton/AppButton'; import '../../_styles/version-modal.scss'; const CreateDraftVersionModal = ({ showCreateAppVersion, setShowCreateAppVersion, handleCommitEnableChange, canCommit, orgGit, fetchingOrgGit, handleCommitOnVersionCreation = () => { }, }) => { const { moduleId } = useModuleContext(); const [isCreatingVersion, setIsCreatingVersion] = useState(false); const [versionName, setVersionName] = useState(''); const [isGitSyncEnabled, setIsGitSyncEnabled] = useState(false); const { createNewVersionAction, changeEditorVersionAction, fetchDevelopmentVersions, developmentVersions, appId, selectedVersion, } = useStore( (state) => ({ createNewVersionAction: state.createNewVersionAction, changeEditorVersionAction: state.changeEditorVersionAction, selectedEnvironment: state.selectedEnvironment, fetchDevelopmentVersions: state.fetchDevelopmentVersions, developmentVersions: state.developmentVersions, featureAccess: state.license.featureAccess, editingVersion: state.currentVersionId, appId: state.appStore.modules[moduleId].app.appId, currentVersionId: state.currentVersionId, selectedVersion: state.selectedVersion, }), shallow ); // Filter out draft versions - show all saved versions (PUBLISHED + any released) const savedVersions = developmentVersions.filter((version) => version.status !== 'DRAFT'); useEffect(() => { const gitSyncEnabled = orgGit?.git_ssh?.is_enabled || orgGit?.git_https?.is_enabled || orgGit?.git_lab?.is_enabled; setIsGitSyncEnabled(gitSyncEnabled); }, [orgGit]); const [selectedVersionForCreation, setSelectedVersionForCreation] = useState(null); useEffect(() => { if (appId) { fetchDevelopmentVersions(appId); } }, [appId, fetchDevelopmentVersions]); useEffect(() => { if (selectedVersionForCreation) { return; } // If savedVersions is empty but we have a selectedVersion that is not DRAFT, use it if (!savedVersions?.length) { if (selectedVersion && selectedVersion.status !== 'DRAFT') { setSelectedVersionForCreation(selectedVersion); } return; } // If selectedVersion exists in savedVersions, use it if (selectedVersion?.id) { const selected = savedVersions.find((version) => version?.id === selectedVersion?.id); if (selected) { setSelectedVersionForCreation(selected); return; } } // Otherwise, default to the first saved version if (savedVersions.length > 0) { setSelectedVersionForCreation(savedVersions[0]); } }, [savedVersions, selectedVersion, selectedVersionForCreation]); // Update version name when selectedVersionForCreation changes or when modal opens useEffect(() => { if (showCreateAppVersion && selectedVersionForCreation?.name) { setVersionName(selectedVersionForCreation.name); } }, [selectedVersionForCreation, showCreateAppVersion]); const { t } = useTranslation(); // Create options from savedVersions (all non-draft versions) const options = savedVersions.length > 0 ? savedVersions.map((version) => ({ label: version.name, value: version.id })) : selectedVersion && selectedVersion.status !== 'DRAFT' ? [{ label: selectedVersion.name, value: selectedVersion.id }] : []; const createVersion = () => { if (versionName.trim().length > 25) { toast.error('Version name should not be longer than 25 characters'); return; } if (versionName.trim() == '') { toast.error('Version name should not be empty'); return; } if (!selectedVersionForCreation || selectedVersionForCreation === undefined) { toast.error('Please select a version from.'); return; } setIsCreatingVersion(true); //TODO: pass environmentId to the func createNewVersionAction( appId, versionName, selectedVersionForCreation.id, '', (newVersion) => { toast.success('Version Created'); setVersionName(''); setIsCreatingVersion(false); setShowCreateAppVersion(false); // Refresh development versions to update the list with the new draft fetchDevelopmentVersions(appId); // Use changeEditorVersionAction to properly switch to the new draft version // This will update selectedVersion with all fields including status changeEditorVersionAction( appId, newVersion.id, (data) => { handleCommitOnVersionCreation(data); }, (error) => { console.error('Error switching to new draft version:', error); toast.error('Draft created but failed to switch to it'); } ); }, (error) => { if (error?.data?.code === '23505') { toast.error('Version name already exists.'); } else { toast.error(error); } setIsCreatingVersion(false); } ); }; return ( { setVersionName(''); setShowCreateAppVersion(false); }} title={t('editor.appVersionManager.createDraftVersion', 'Create draft version')} customClassName="create-draft-version-modal" > {fetchingOrgGit ? (
) : (
{ e.preventDefault(); createVersion(); }} >
setVersionName(e.target.value)} className="form-control" data-cy="version-name-input-field" placeholder={t('editor.appVersionManager.enterVersionName', 'Enter version name')} disabled={isCreatingVersion} value={versionName} autoFocus={true} minLength="1" maxLength="25" style={{ height: '32px' }} /> {t('editor.appVersionManager.versionNameHelper', 'Version name must be unique and max 25 characters')}
Commit changes
This will commit the creation of the new version to the git repo
)}

{ setVersionName(''); setShowCreateAppVersion(false); }} variant="tertiary" className="mx-2" data-cy="create-draft-version-cancel-button" > {t('globals.cancel', 'Cancel')} {t('editor.appVersionManager.createVersion', 'Create Version')}
)} ); }; export default CreateDraftVersionModal;