import { useState, useEffect, useRef } from 'react' import { useTranslation } from 'react-i18next' import getMeta from '@/utils/meta' import { postJSON } from '@/infrastructure/fetch-json' import { useDetachCompileContext as useCompileContext } from '@/shared/context/detach-compile-context' import OLButton from '@/shared/components/ol/ol-button' import OLFormControl from '@/shared/components/ol/ol-form-control' import OLFormGroup from '@/shared/components/ol/ol-form-group' import OLFormLabel from '@/shared/components/ol/ol-form-label' import { FormCheck } from 'react-bootstrap' import MaterialIcon from '@/shared/components/material-icon' import OLNotification from '@/shared/components/ol/ol-notification' type Action = 'save' | 'push' | 'pull' type Status = 'idle' | 'busy' | 'success' | 'error' const projectId = getMeta('ol-project_id') const AUTO_PUSH_KEY = `gitSync.autoPushOnCompile.${projectId}` export default function GitSyncWidget() { const { t } = useTranslation() const { compiling, error: compileError, pdfFile, clsiServerId } = useCompileContext() const [remoteUrl, setRemoteUrl] = useState(getMeta('ol-gitRemote') ?? '') const [subPath, setSubPath] = useState(getMeta('ol-gitSyncPath') ?? '') const [pdfPath, setPdfPath] = useState(getMeta('ol-gitSyncPdfPath') ?? '') const [pushFiles, setPushFiles] = useState(getMeta('ol-gitSyncPushFiles') ?? true) const [pushPdf, setPushPdf] = useState(getMeta('ol-gitSyncPushPdf') ?? true) const [autoPush, setAutoPush] = useState( () => localStorage.getItem(AUTO_PUSH_KEY) === 'true' ) const [lastAction, setLastAction] = useState('save') const [status, setStatus] = useState('idle') const [errorMsg, setErrorMsg] = useState('') const wasCompilingRef = useRef(false) const isBusyRef = useRef(false) useEffect(() => { isBusyRef.current = status === 'busy' }, [status]) // Auto-push when compile finishes successfully useEffect(() => { const wasCompiling = wasCompilingRef.current wasCompilingRef.current = compiling if ( wasCompiling && !compiling && !compileError && autoPush && !isBusyRef.current ) { doPush(pdfFile?.build, clsiServerId) } }, [compiling]) // eslint-disable-line react-hooks/exhaustive-deps async function saveConfig() { await postJSON(`/project/${projectId}/git-sync`, { body: { remoteUrl, subPath, pdfPath, pushFiles, pushPdf }, }) } function extractError(err: any): string { return err?.data?.error ?? err?.message ?? String(err) } async function doPush(buildId?: string, serverId?: string) { setLastAction('push') setStatus('busy') setErrorMsg('') try { await saveConfig() await postJSON(`/project/${projectId}/git-sync/push`, { body: { buildId, clsiServerId: serverId }, }) setStatus('success') } catch (err: any) { setStatus('error') setErrorMsg(extractError(err)) } } async function handleSave(e: React.FormEvent) { e.preventDefault() setLastAction('save') setStatus('busy') setErrorMsg('') try { await saveConfig() setStatus('success') } catch (err: any) { setStatus('error') setErrorMsg(extractError(err)) } } function handlePush() { doPush(pdfFile?.build, clsiServerId) } async function handlePull() { setLastAction('pull') setStatus('busy') setErrorMsg('') try { await saveConfig() await postJSON(`/project/${projectId}/git-sync/pull`, { body: {} }) setStatus('success') } catch (err: any) { setStatus('error') setErrorMsg(extractError(err)) } } function handleAutoPushToggle(e: React.ChangeEvent) { const checked = e.target.checked setAutoPush(checked) localStorage.setItem(AUTO_PUSH_KEY, String(checked)) } const isBusy = status === 'busy' const nothingToPush = !pushFiles && (!pushPdf || !pdfPath.trim()) return (
{t('git_sync')}

{t('git_sync_description')}

{t('git_sync_remote_url')} setRemoteUrl(e.target.value)} placeholder="https://user:token@github.com/org/repo.git" disabled={isBusy} /> {t('git_sync_sub_path')} setSubPath(e.target.value)} placeholder={t('git_sync_sub_path_placeholder')} disabled={isBusy} /> setPushFiles(e.target.checked)} disabled={isBusy} /> {t('git_sync_pdf_path')} setPdfPath(e.target.value)} placeholder={t('git_sync_pdf_path_placeholder')} disabled={isBusy} /> setPushPdf(e.target.checked)} disabled={isBusy || !pdfPath.trim()} />
{t('save')} {t('git_sync_push_now')} {t('git_sync_pull_now')}
{status === 'success' && ( )} {status === 'error' && ( )}
) }