nitro-v36-with-renderer-v36
/
src /
components /
catalog /
admin /
studio /
CatalogStudioTransferPanel.tsx
CatalogStudioTransferPanel.tsx 4.8 Ko
Télécharger le fichier
import { ChangeEvent, FC, useEffect, useRef, useState } from 'react';
import { FaDownload, FaFileImport, FaUpload } from 'react-icons/fa';
import { useCatalogStudio } from './useCatalogStudio';
import { BaseButton } from '../../../../common/BaseButton';
const CATALOG_FILE_NAME = 'catalog-studio.sql';
const downloadDocument = (document: string) => {
const url = URL.createObjectURL(new Blob([ document ], { type: 'application/sql;charset=utf-8' }));
const link = window.document.createElement('a');
link.href = url;
link.download = CATALOG_FILE_NAME;
link.click();
// Revoked at once, the URL could be gone before the browser started the download.
window.setTimeout(() => URL.revokeObjectURL(url), 1000);
};
export const CatalogStudioTransferPanel: FC = () => {
const studio = useCatalogStudio();
const [document, setDocument] = useState('');
const downloadPending = useRef(false);
const result = studio.documentResult?.format === 'SQL' ? studio.documentResult : null;
useEffect(() => {
if (result?.code !== 'EXPORTED' || !result.document) return;
setDocument(result.document);
if (downloadPending.current) {
downloadPending.current = false;
downloadDocument(result.document);
}
}, [result?.operationId]);
const importFile = (event: ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
event.target.value = '';
if (!file) return;
const reader = new FileReader();
reader.addEventListener('load', () => setDocument(String(reader.result ?? '')));
reader.readAsText(file);
};
const requestDownload = () => {
downloadPending.current = true;
studio.exportDocument('SQL');
};
return <div className="octane-catalog-admin-import-export">
<div className="octane-catalog-admin-section-head">
<div>
<strong>Import or export the full catalog</strong>
<span>Pages and offers travel together in one validated SQL file. Statements are parsed safely and never executed directly.</span>
</div>
</div>
<div className="octane-catalog-admin-import-toolbar">
<label className="octane-catalog-admin-btn" htmlFor="catalog-studio-file-import">
<FaFileImport /> Import file
</label>
<input
id="catalog-studio-file-import"
className="d-none"
type="file"
accept=".sql,application/sql,text/plain"
aria-label="Import catalog SQL file"
onChange={importFile}
/>
<BaseButton className="octane-catalog-admin-btn" disabled={studio.loading} onClick={requestDownload}>
<FaDownload /> Download full catalog
</BaseButton>
<BaseButton
className="octane-catalog-admin-btn"
disabled={studio.loading || !document.trim()}
onClick={() => studio.dryRunDocument('SQL', document)}
>
Validate and dry-run
</BaseButton>
<BaseButton
className="octane-catalog-admin-btn is-publish"
disabled={studio.loading || result?.code !== 'DRY_RUN_READY' || result.changedEntities === 0}
onClick={() => result && studio.applyDocument('SQL', document, result.fingerprint, 'Import catalog SQL file')}
>
<FaUpload /> Apply {result?.changedEntities ?? 0} changes
</BaseButton>
</div>
<textarea
value={document}
onChange={event => setDocument(event.target.value)}
spellCheck={false}
aria-label="SQL catalog document"
placeholder="Import a .sql file or paste a complete catalog export here."
/>
{result && <div role="status" className={`octane-catalog-admin-publish-status ${result.success ? 'is-ready' : 'is-blocked'}`}>
{result.message} · {result.changedEntities} change(s)
</div>}
{!!result?.changes.length && <div className="octane-catalog-admin-validation-list" aria-label="SQL field diff">
<div className="octane-catalog-admin-publish-changes-head">Dry-run field diff</div>
{result.changes.map(change => <div
className="octane-catalog-admin-history-row"
key={`${change.catalogType}-${change.entityType}-${change.entityId}-${change.operation}`}
>
<div className="octane-catalog-admin-history-main">
<strong>{change.operation} {change.entityType} #{change.entityId}</strong>
<span>{change.catalogType} · {change.fields.length ? change.fields.join(', ') : 'no field changes'}</span>
</div>
</div>)}
</div>}
</div>;
};
