abort and search

This commit is contained in:
seb
2026-09-19 08:14:11 +02:00
parent abe078ff05
commit d3b4743b66
9 changed files with 690 additions and 76 deletions

View File

@@ -19,6 +19,7 @@ import {
lineFromApi,
manifestConfig,
TextEditorDialog,
ArticleSearchDialog,
} from '../../components/manifest';
import ManifestPdfDialog from '../../components/manifest/ManifestPdfDialog';
import { loadParties } from '../../components/manifest/manifestConfig';
@@ -50,6 +51,8 @@ class LieferungNeuPage extends PureComponent {
pdfFileName: '',
textEditorOpen: false,
textEditorAttachment: null,
articleSearchDialogOpen: false,
articleSearchLine: null,
};
this._cancelled = false;
this.handleRetry = this.handleRetry.bind(this);
@@ -65,6 +68,7 @@ class LieferungNeuPage extends PureComponent {
this.handlePdfRescan = this.handlePdfRescan.bind(this);
this.handlePdfDelete = this.handlePdfDelete.bind(this);
this.handleClosePdfDialog = this.handleClosePdfDialog.bind(this);
this.handleAbortParse = this.handleAbortParse.bind(this);
this.handleAttachmentClick = this.handleAttachmentClick.bind(this);
this.handleCloseTextEditor = this.handleCloseTextEditor.bind(this);
this.handleSaveTextEditor = this.handleSaveTextEditor.bind(this);
@@ -72,6 +76,9 @@ class LieferungNeuPage extends PureComponent {
this.ensureAttachmentFile = this.ensureAttachmentFile.bind(this);
this.handleSkuBlur = this.handleSkuBlur.bind(this);
this.handleCreateArticleForLine = this.handleCreateArticleForLine.bind(this);
this.handleOpenArticleSearchForLine = this.handleOpenArticleSearchForLine.bind(this);
this.handleCloseArticleSearch = this.handleCloseArticleSearch.bind(this);
this.handleAssignArticleForLine = this.handleAssignArticleForLine.bind(this);
}
componentDidMount() {
@@ -106,6 +113,10 @@ class LieferungNeuPage extends PureComponent {
componentWillUnmount() {
this._cancelled = true;
if (this._parseAbortController) {
this._parseAbortController.abort();
this._parseAbortController = null;
}
if (this._skuDebounceTimers) {
Object.values(this._skuDebounceTimers).forEach(clearTimeout);
this._skuDebounceTimers = null;
@@ -311,6 +322,67 @@ class LieferungNeuPage extends PureComponent {
}
}
handleOpenArticleSearchForLine(line) {
this.setState({
articleSearchDialogOpen: true,
articleSearchLine: line,
});
}
handleCloseArticleSearch() {
this.setState({
articleSearchDialogOpen: false,
articleSearchLine: null,
});
}
async handleAssignArticleForLine(article, line) {
const { partyId } = this.state;
if (!partyId) {
enqueueSnackbar('Bitte wählen Sie zuerst einen Lieferanten aus.', { variant: 'warning' });
return;
}
const internalSku = article?.sku;
if (!internalSku) {
enqueueSnackbar('Artikel hat keine SKU.', { variant: 'error' });
return;
}
const supplierSku = line?.sku;
try {
await this.context.article.addSupplier(internalSku, {
entityId: partyId,
sku: supplierSku || undefined,
pu: line?.pu ? Number(line.pu) : undefined,
stock: line?.amount ? Number(line.amount) : undefined,
netPrice: line?.netprice ? Number(line.netprice) : undefined,
taxRate: line?.taxrate ? Number(line.taxrate) : undefined,
});
if (supplierSku) {
this.automat.actions.fetchSupplierArticleForSku(supplierSku, line.key);
} else {
this.automat.actions.fetchSupplierArticles(partyId);
}
enqueueSnackbar(
`Lieferant erfolgreich dem Artikel "${internalSku}" zugeordnet.`,
{ variant: 'success' },
);
this.setState({
articleSearchDialogOpen: false,
articleSearchLine: null,
});
} catch (err) {
console.error('Fehler beim Zuordnen des Artikels:', err);
notifyError(err);
throw err;
}
}
handleAddLine() {
this.automat.actions.addLineitem();
}
@@ -451,15 +523,21 @@ class LieferungNeuPage extends PureComponent {
}
async runParse(file) {
if (this._parseAbortController) {
this._parseAbortController.abort();
}
const abortController = new AbortController();
this._parseAbortController = abortController;
this.setState({
pdfUploading: true,
pdfDialogOpen: true,
pdfFileName: file.name,
pdfDialogData: { streaming: true, messages: [], result: null, error: null },
pdfDialogData: { streaming: true, messages: [], result: null, error: null, aborted: false },
});
const appendMessage = (msg) => {
if (this._cancelled) return;
if (this._cancelled || abortController.signal.aborted) return;
this.setState((prev) => ({
pdfDialogData: {
...prev.pdfDialogData,
@@ -472,8 +550,8 @@ class LieferungNeuPage extends PureComponent {
const parser = this.context?.delivery?.parseSse;
if (!parser) throw new Error('parseSse nicht verfügbar.');
for await (const { event, data } of parser(file)) {
if (this._cancelled) return;
for await (const { event, data } of parser(file, { signal: abortController.signal })) {
if (this._cancelled || abortController.signal.aborted) return;
switch (event) {
case 'status':
appendMessage({ type: 'status', text: data.message ?? String(data) });
@@ -580,6 +658,17 @@ class LieferungNeuPage extends PureComponent {
}
} catch (err) {
if (this._cancelled) return;
if (abortController.signal.aborted || err.name === 'AbortError') {
this.setState((prev) => ({
pdfDialogData: {
...prev.pdfDialogData,
streaming: false,
aborted: true,
error: 'Analyse abgebrochen.',
},
}));
return;
}
this.setState((prev) => ({
pdfDialogData: {
...prev.pdfDialogData,
@@ -588,6 +677,9 @@ class LieferungNeuPage extends PureComponent {
},
}));
} finally {
if (this._parseAbortController === abortController) {
this._parseAbortController = null;
}
if (!this._cancelled) {
this.setState((prev) => ({
pdfUploading: false,
@@ -607,8 +699,30 @@ class LieferungNeuPage extends PureComponent {
await this.runParse(file);
}
handleAbortParse() {
if (this._parseAbortController) {
this._parseAbortController.abort();
this._parseAbortController = null;
}
this.setState((prev) => ({
pdfUploading: false,
pdfDialogData: prev.pdfDialogData
? {
...prev.pdfDialogData,
streaming: false,
aborted: true,
error: 'Analyse abgebrochen.',
}
: null,
}));
}
handleClosePdfDialog() {
this.setState({ pdfDialogOpen: false });
if (this._parseAbortController) {
this._parseAbortController.abort();
this._parseAbortController = null;
}
this.setState({ pdfDialogOpen: false, pdfUploading: false });
}
async ensureAttachmentFile(attachment) {
@@ -929,6 +1043,7 @@ class LieferungNeuPage extends PureComponent {
onRemoveLine={this.handleRemoveLine}
onSave={() => void this.handleSave()}
onCreateArticle={this.handleCreateArticleForLine}
onSearchArticle={this.handleOpenArticleSearchForLine}
/>
</>
)}
@@ -952,6 +1067,7 @@ class LieferungNeuPage extends PureComponent {
filename={pdfFileName}
data={pdfDialogData}
onClose={this.handleClosePdfDialog}
onAbort={this.handleAbortParse}
/>
<TextEditorDialog
open={this.state.textEditorOpen}
@@ -961,6 +1077,12 @@ class LieferungNeuPage extends PureComponent {
onSave={this.handleSaveTextEditor}
onContentLoad={this.handleTextEditorContentLoaded}
/>
<ArticleSearchDialog
open={this.state.articleSearchDialogOpen}
line={this.state.articleSearchLine}
onClose={this.handleCloseArticleSearch}
onAssign={this.handleAssignArticleForLine}
/>
</>
);
}