u
This commit is contained in:
@@ -26,10 +26,6 @@ import brandAutomat from '../../automats/brandAutomat';
|
||||
import { orderAutomat } from '../../automats/orderAutomat';
|
||||
import SkeleHashImage from './SkeleHashImage';
|
||||
|
||||
// Keep only the most recent N image events in state to avoid unbounded growth
|
||||
// on large imports (thousands of images).
|
||||
const MAX_STREAMED_IMAGES = 60;
|
||||
|
||||
function formatBytes(bytes) {
|
||||
if (bytes == null || isNaN(bytes) || bytes === 0) return '0 B';
|
||||
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
@@ -104,8 +100,8 @@ export default class ImportExportSettingsPanel extends Component {
|
||||
uploadLoaded: 0,
|
||||
uploadTotal: 0,
|
||||
importProgress: null, // raw counters from the `progress` event
|
||||
// Most recent SkeleHashes from the stream ({ id, hash })
|
||||
importedImages: [],
|
||||
// Latest SkeleHash shown (first hash of the most recent images batch)
|
||||
streamedHash: null,
|
||||
importedImageCount: 0,
|
||||
statusMessage: null,
|
||||
importStats: null,
|
||||
@@ -252,7 +248,6 @@ export default class ImportExportSettingsPanel extends Component {
|
||||
|
||||
this.uploadAbortController = new AbortController();
|
||||
|
||||
this.imageSeq = 0;
|
||||
this.setState({
|
||||
uploading: true,
|
||||
uploadStage: 'upload',
|
||||
@@ -260,7 +255,7 @@ export default class ImportExportSettingsPanel extends Component {
|
||||
uploadLoaded: 0,
|
||||
uploadTotal: selectedFile.size,
|
||||
importProgress: null,
|
||||
importedImages: [],
|
||||
streamedHash: null,
|
||||
importedImageCount: 0,
|
||||
statusMessage: null,
|
||||
importStats: null,
|
||||
@@ -294,25 +289,16 @@ export default class ImportExportSettingsPanel extends Component {
|
||||
onImages: (images) => {
|
||||
const list = Array.isArray(images) ? images.filter(Boolean) : [];
|
||||
if (!list.length) return;
|
||||
this.setState((prev) => {
|
||||
let seq = this.imageSeq ?? 0;
|
||||
const batch = list.map((item) => {
|
||||
seq += 1;
|
||||
return {
|
||||
id: seq,
|
||||
hash: typeof item === 'string' ? item : (item?.skelehash ?? null),
|
||||
};
|
||||
});
|
||||
this.imageSeq = seq;
|
||||
const next = [...batch.reverse(), ...prev.importedImages];
|
||||
if (next.length > MAX_STREAMED_IMAGES) next.length = MAX_STREAMED_IMAGES;
|
||||
return {
|
||||
uploadStage: 'server',
|
||||
importedImages: next,
|
||||
importedImageCount: prev.importedImageCount + list.length,
|
||||
statusMessage: null,
|
||||
};
|
||||
});
|
||||
// Only the first hash of each batch; it replaces the previously
|
||||
// shown placeholder.
|
||||
const first = list[0];
|
||||
const hash = typeof first === 'string' ? first : (first?.skelehash ?? null);
|
||||
this.setState((prev) => ({
|
||||
uploadStage: 'server',
|
||||
streamedHash: hash,
|
||||
importedImageCount: prev.importedImageCount + list.length,
|
||||
statusMessage: null,
|
||||
}));
|
||||
},
|
||||
onDone: (stats) => {
|
||||
this.setState({
|
||||
@@ -383,7 +369,7 @@ export default class ImportExportSettingsPanel extends Component {
|
||||
uploadLoaded,
|
||||
uploadTotal,
|
||||
importProgress,
|
||||
importedImages,
|
||||
streamedHash,
|
||||
importedImageCount,
|
||||
statusMessage,
|
||||
importStats,
|
||||
@@ -831,88 +817,44 @@ export default class ImportExportSettingsPanel extends Component {
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Live stream of decoded SkeleHash placeholders */}
|
||||
{importedImages.length > 0 && (
|
||||
<Box sx={{ mt: 2, pt: 2, borderTop: '1px dashed', borderColor: 'divider' }}>
|
||||
{/* Latest decoded SkeleHash placeholder (replaces previous) */}
|
||||
{streamedHash && (
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 1,
|
||||
mt: 2,
|
||||
pt: 2,
|
||||
borderTop: '1px dashed',
|
||||
borderColor: 'divider',
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
title={streamedHash}
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
mb: 1,
|
||||
width: 36,
|
||||
height: 36,
|
||||
flex: '0 0 auto',
|
||||
borderRadius: 1,
|
||||
overflow: 'hidden',
|
||||
border: '1px solid',
|
||||
borderColor: 'divider',
|
||||
bgcolor: 'background.paper',
|
||||
}}
|
||||
>
|
||||
<Typography variant="caption" fontWeight={600} color="text.secondary">
|
||||
SkeleHash-Platzhalter (Vorschau)
|
||||
</Typography>
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
{importedImageCount} Bild(er) verarbeitet
|
||||
</Typography>
|
||||
<SkeleHashImage hash={streamedHash} />
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'repeat(auto-fill, minmax(72px, 1fr))',
|
||||
gap: 1,
|
||||
maxHeight: 220,
|
||||
overflowY: 'auto',
|
||||
}}
|
||||
<Typography
|
||||
variant="caption"
|
||||
color="text.secondary"
|
||||
sx={{ fontFamily: 'monospace' }}
|
||||
>
|
||||
{importedImages.map((image) => (
|
||||
<Box
|
||||
key={image.id}
|
||||
title={image.hash || 'kein Hash'}
|
||||
sx={{
|
||||
position: 'relative',
|
||||
aspectRatio: '1 / 1',
|
||||
borderRadius: 1,
|
||||
overflow: 'hidden',
|
||||
border: '1px solid',
|
||||
borderColor: 'divider',
|
||||
bgcolor: 'background.paper',
|
||||
}}
|
||||
>
|
||||
{image.hash ? (
|
||||
<SkeleHashImage hash={image.hash} />
|
||||
) : (
|
||||
<Box
|
||||
sx={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
color: 'text.disabled',
|
||||
fontSize: '0.6rem',
|
||||
textAlign: 'center',
|
||||
p: 0.5,
|
||||
}}
|
||||
>
|
||||
Kein Hash
|
||||
</Box>
|
||||
)}
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
inset: 'auto 0 0 0',
|
||||
bgcolor: 'rgba(0,0,0,0.55)',
|
||||
color: '#fff',
|
||||
px: 0.5,
|
||||
py: 0.25,
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
variant="caption"
|
||||
noWrap
|
||||
display="block"
|
||||
sx={{ fontSize: '0.6rem', lineHeight: 1.2, fontFamily: 'monospace' }}
|
||||
>
|
||||
{shortHash(image.hash)}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
{shortHash(streamedHash)}
|
||||
</Typography>
|
||||
<Typography variant="caption" color="text.secondary" sx={{ ml: 'auto' }}>
|
||||
{importedImageCount} Bild(er) verarbeitet
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user