u
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import { resolve, dirname } from 'node:path';
|
||||
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import decodeAvif, { init as initAvifDecode } from '@jsquash/avif/decode.js';
|
||||
import encodeAvif, { init as initAvifEncode } from '@jsquash/avif/encode.js';
|
||||
import encodeJpeg, { init as initJpegEncode } from '@jsquash/jpeg/encode.js';
|
||||
|
||||
@@ -798,7 +798,7 @@ export class StorageManager extends ApiClient {
|
||||
return requireArray(data.orders, 'orders');
|
||||
}
|
||||
|
||||
async doSearch({ target, filter, offset, maxCount, onUpdate }) {
|
||||
async doSearch({ target, onUpdate }) {
|
||||
const articles = await this.articleIndexPromise;
|
||||
const query = target.trim().toLowerCase();
|
||||
const matches = articles.filter(
|
||||
|
||||
@@ -5,7 +5,6 @@ import companyAutomat from './companyAutomat';
|
||||
import {
|
||||
parseCategoryTreeResponse,
|
||||
normalizeCategoryNode,
|
||||
getCategoryBreadcrumbs,
|
||||
getCategoryChildren,
|
||||
cleanCategorySlugPath,
|
||||
resolveCategoryIdFromSlugPath,
|
||||
@@ -94,7 +93,7 @@ function refreshLoadedCategoryViewChildren(categories) {
|
||||
* Get or create a per-route category view automat for the given slug and categoryId.
|
||||
* (Backward compatibility helper)
|
||||
*/
|
||||
export function getOrCreateCategoryAutomat({ slugPath, categoryId }) {
|
||||
export function getOrCreateCategoryAutomat({ slugPath }) {
|
||||
const slug = cleanCategorySlugPath(slugPath);
|
||||
return categoryViews.key(slug);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ import Box from '@mui/material/Box';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import Tab from '@mui/material/Tab';
|
||||
import Tabs from '@mui/material/Tabs';
|
||||
import AccountTreeIcon from '@mui/icons-material/AccountTree';
|
||||
import CategoryIcon from '@mui/icons-material/Category';
|
||||
import HistoryIcon from '@mui/icons-material/History';
|
||||
import LabelIcon from '@mui/icons-material/Label';
|
||||
|
||||
@@ -45,7 +45,7 @@ export default class CategoryPickerDialog extends PureComponent {
|
||||
componentDidMount() {
|
||||
if (this.props.categories === undefined || this.props.rootCategoryId === undefined) {
|
||||
this._unsub = categoryAutomat.subscribe((s) => {
|
||||
this.setState((prev) => ({
|
||||
this.setState(() => ({
|
||||
categories: this.props.categories ?? s.categories,
|
||||
rootCategoryId: this.props.rootCategoryId ?? s.rootCategoryId,
|
||||
}));
|
||||
@@ -132,7 +132,6 @@ export default class CategoryPickerDialog extends PureComponent {
|
||||
const dialogTitle = title || (mode === 'single' ? 'Kategorie auswählen' : 'Kategorie zuweisen');
|
||||
const actionLabel = confirmLabel || (mode === 'single' ? 'Auswählen' : 'Zuweisen');
|
||||
|
||||
const selectedNode = categories && selectedId != null ? categories[String(selectedId)] : null;
|
||||
const isAlreadyAssigned =
|
||||
mode !== 'single' && currentCategoryIds.some((id) => String(id) === String(selectedId));
|
||||
const isSelectedDisabled =
|
||||
|
||||
@@ -366,22 +366,20 @@ export default class ArticleViewLists extends PureComponent {
|
||||
const count = Math.max(1, Number(stuecklisteCount) || 1);
|
||||
|
||||
const existingIndex = currentItems.findIndex((i) => i.sku === stuecklisteTargetArticle.sku);
|
||||
let nextItems = [];
|
||||
if (existingIndex >= 0) {
|
||||
nextItems = currentItems.map((item, idx) =>
|
||||
idx === existingIndex ? { ...item, count: item.count + count } : item
|
||||
);
|
||||
} else {
|
||||
nextItems = [
|
||||
...currentItems,
|
||||
{
|
||||
articleId: stuecklisteTargetArticle.id,
|
||||
sku: stuecklisteTargetArticle.sku,
|
||||
count,
|
||||
sort: currentItems.length,
|
||||
},
|
||||
];
|
||||
}
|
||||
const nextItems =
|
||||
existingIndex >= 0
|
||||
? currentItems.map((item, idx) =>
|
||||
idx === existingIndex ? { ...item, count: item.count + count } : item
|
||||
)
|
||||
: [
|
||||
...currentItems,
|
||||
{
|
||||
articleId: stuecklisteTargetArticle.id,
|
||||
sku: stuecklisteTargetArticle.sku,
|
||||
count,
|
||||
sort: currentItems.length,
|
||||
},
|
||||
];
|
||||
|
||||
this.setState({ busy: true });
|
||||
try {
|
||||
@@ -492,25 +490,23 @@ export default class ArticleViewLists extends PureComponent {
|
||||
const count = Math.max(1, Number(optionCount) || 1);
|
||||
|
||||
const existingIndex = currentOptions.findIndex((o) => o.sku === optionTargetArticle.sku);
|
||||
let nextOptions = [];
|
||||
if (existingIndex >= 0) {
|
||||
nextOptions = currentOptions.map((opt, idx) =>
|
||||
idx === existingIndex
|
||||
? { ...opt, count: opt.count + count, mandated: Boolean(optionMandated) }
|
||||
: opt
|
||||
);
|
||||
} else {
|
||||
nextOptions = [
|
||||
...currentOptions,
|
||||
{
|
||||
articleId: optionTargetArticle.id,
|
||||
sku: optionTargetArticle.sku,
|
||||
count,
|
||||
sort: currentOptions.length,
|
||||
mandated: Boolean(optionMandated),
|
||||
},
|
||||
];
|
||||
}
|
||||
const nextOptions =
|
||||
existingIndex >= 0
|
||||
? currentOptions.map((opt, idx) =>
|
||||
idx === existingIndex
|
||||
? { ...opt, count: opt.count + count, mandated: Boolean(optionMandated) }
|
||||
: opt
|
||||
)
|
||||
: [
|
||||
...currentOptions,
|
||||
{
|
||||
articleId: optionTargetArticle.id,
|
||||
sku: optionTargetArticle.sku,
|
||||
count,
|
||||
sort: currentOptions.length,
|
||||
mandated: Boolean(optionMandated),
|
||||
},
|
||||
];
|
||||
|
||||
this.setState({ busy: true });
|
||||
try {
|
||||
@@ -1363,15 +1359,9 @@ export default class ArticleViewLists extends PureComponent {
|
||||
busy,
|
||||
activeCreatorMode,
|
||||
activeListTab,
|
||||
selectedAttributeId,
|
||||
selectedChildValueId,
|
||||
newChildText,
|
||||
isCustomChildValue,
|
||||
stuecklisteTargetArticle,
|
||||
stuecklisteCount,
|
||||
optionTargetArticle,
|
||||
optionCount,
|
||||
optionMandated,
|
||||
removeTargetChild,
|
||||
confirmClearType,
|
||||
} = this.state;
|
||||
|
||||
@@ -184,13 +184,14 @@ export default class ArticleAttributesTab extends PureComponent {
|
||||
return;
|
||||
}
|
||||
|
||||
let nextValues = [];
|
||||
if (isExclusive) {
|
||||
const others = assignedAttributes.filter((a) => a.attributeId !== targetAttr.id);
|
||||
nextValues = [...others.map((a) => a.attributeValueId), targetValId];
|
||||
} else {
|
||||
nextValues = [...assignedAttributes.map((a) => a.attributeValueId), targetValId];
|
||||
}
|
||||
const nextValues = isExclusive
|
||||
? [
|
||||
...assignedAttributes
|
||||
.filter((a) => a.attributeId !== targetAttr.id)
|
||||
.map((a) => a.attributeValueId),
|
||||
targetValId,
|
||||
]
|
||||
: [...assignedAttributes.map((a) => a.attributeValueId), targetValId];
|
||||
|
||||
this.setState({ saving: true });
|
||||
try {
|
||||
@@ -222,19 +223,13 @@ export default class ArticleAttributesTab extends PureComponent {
|
||||
return;
|
||||
}
|
||||
}
|
||||
let nextProps = [];
|
||||
if (isExclusive) {
|
||||
const existing = assignedProperties.filter((p) => p.propertyId !== propId);
|
||||
nextProps = [
|
||||
...existing.map((p) => ({ propertyId: p.propertyId, value: p.value, sort: p.sort })),
|
||||
{ propertyId: propId, value: val },
|
||||
];
|
||||
} else {
|
||||
nextProps = [
|
||||
...assignedProperties.map((p) => ({ propertyId: p.propertyId, value: p.value, sort: p.sort })),
|
||||
{ propertyId: propId, value: val },
|
||||
];
|
||||
}
|
||||
const sourceProps = isExclusive
|
||||
? assignedProperties.filter((p) => p.propertyId !== propId)
|
||||
: assignedProperties;
|
||||
const nextProps = [
|
||||
...sourceProps.map((p) => ({ propertyId: p.propertyId, value: p.value, sort: p.sort })),
|
||||
{ propertyId: propId, value: val },
|
||||
];
|
||||
|
||||
this.setState({ saving: true });
|
||||
try {
|
||||
|
||||
@@ -43,7 +43,7 @@ function getMatchingAndAncestorIds(categories, query, rootCategoryId, excludeIds
|
||||
if (!categories || !query.trim()) return matches;
|
||||
const q = query.trim().toLowerCase();
|
||||
|
||||
for (const [idStr, node] of Object.entries(categories)) {
|
||||
for (const node of Object.values(categories)) {
|
||||
if (excludeIds.some((id) => String(id) === String(node.id))) continue;
|
||||
const label = categoryDisplayName(node.name, node.id, rootCategoryId).toLowerCase();
|
||||
if (label.includes(q)) {
|
||||
@@ -580,7 +580,6 @@ export default class CategoryTree extends PureComponent {
|
||||
addCategoryName,
|
||||
isSubmitting,
|
||||
renameDialogOpen,
|
||||
renameNode,
|
||||
renameValue,
|
||||
deleteDialogOpen,
|
||||
deleteNode,
|
||||
|
||||
@@ -2,7 +2,6 @@ import {
|
||||
ROOT_CATEGORY_NAME,
|
||||
categorySlug,
|
||||
getCategoryBreadcrumbs,
|
||||
getCategoryChildren,
|
||||
} from '../../utils/categoryUtils';
|
||||
|
||||
export { ROOT_CATEGORY_NAME, categorySlug };
|
||||
|
||||
@@ -9,7 +9,6 @@ import MenuItem from '@mui/material/MenuItem';
|
||||
import Select from '@mui/material/Select';
|
||||
import FormControl from '@mui/material/FormControl';
|
||||
import InputLabel from '@mui/material/InputLabel';
|
||||
import Chip from '@mui/material/Chip';
|
||||
import CircularProgress from '@mui/material/CircularProgress';
|
||||
import CloseRoundedIcon from '@mui/icons-material/CloseRounded';
|
||||
import SendRoundedIcon from '@mui/icons-material/SendRounded';
|
||||
@@ -231,7 +230,6 @@ export default class ChatDrawer extends PureComponent {
|
||||
const {
|
||||
conversations,
|
||||
selectedConversationId,
|
||||
sseStatus,
|
||||
loadingConversations,
|
||||
} = this.state;
|
||||
|
||||
@@ -249,21 +247,8 @@ export default class ChatDrawer extends PureComponent {
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1.25 }}>
|
||||
<Box
|
||||
sx={{
|
||||
width: 32,
|
||||
height: 32,
|
||||
borderRadius: 2,
|
||||
bgcolor: 'primary.main',
|
||||
color: 'primary.contrastText',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
<AutoAwesomeRoundedIcon sx={{ fontSize: 18 }} />
|
||||
</Box>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||
<AutoAwesomeRoundedIcon sx={{ fontSize: 22, color: 'primary.main' }} />
|
||||
<Typography variant="subtitle1" fontWeight={700}>
|
||||
KI-Assistent
|
||||
</Typography>
|
||||
@@ -275,80 +260,82 @@ export default class ChatDrawer extends PureComponent {
|
||||
</Box>
|
||||
|
||||
{/* Conversation Selector Bar */}
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||
<FormControl fullWidth size="small">
|
||||
<InputLabel id="chat-conversation-label">Konversation</InputLabel>
|
||||
<Select
|
||||
labelId="chat-conversation-label"
|
||||
value={selectedConversationId || ''}
|
||||
label="Konversation"
|
||||
onChange={this.handleSelectConversation}
|
||||
disabled={loadingConversations || conversations.length === 0}
|
||||
sx={{ borderRadius: 2 }}
|
||||
renderValue={(selectedId) => {
|
||||
const conv = conversations.find((c) => c.id === selectedId);
|
||||
if (!conv) return '';
|
||||
return (
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, overflow: 'hidden' }}>
|
||||
<Typography variant="body2" fontWeight={600} noWrap>
|
||||
#{conv.id}
|
||||
</Typography>
|
||||
<Typography variant="caption" color="text.secondary" noWrap>
|
||||
{conv.model || 'Standard'}
|
||||
</Typography>
|
||||
</Box>
|
||||
);
|
||||
{conversations.length > 0 && (
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||
<FormControl fullWidth size="small">
|
||||
<InputLabel id="chat-conversation-label">Konversation</InputLabel>
|
||||
<Select
|
||||
labelId="chat-conversation-label"
|
||||
value={selectedConversationId || ''}
|
||||
label="Konversation"
|
||||
onChange={this.handleSelectConversation}
|
||||
disabled={loadingConversations || conversations.length === 0}
|
||||
sx={{ borderRadius: 2 }}
|
||||
renderValue={(selectedId) => {
|
||||
const conv = conversations.find((c) => c.id === selectedId);
|
||||
if (!conv) return '';
|
||||
return (
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, overflow: 'hidden' }}>
|
||||
<Typography variant="body2" fontWeight={600} noWrap>
|
||||
#{conv.id}
|
||||
</Typography>
|
||||
<Typography variant="caption" color="text.secondary" noWrap>
|
||||
{conv.model || 'Standard'}
|
||||
</Typography>
|
||||
</Box>
|
||||
);
|
||||
}}
|
||||
>
|
||||
{conversations.map((c) => (
|
||||
<MenuItem key={c.id} value={c.id}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, width: '100%', overflow: 'hidden' }}>
|
||||
<Typography variant="body2" fontWeight={600} noWrap>
|
||||
#{c.id}
|
||||
</Typography>
|
||||
<Typography variant="caption" color="text.secondary" noWrap sx={{ flexGrow: 1 }}>
|
||||
{c.model || 'Standard'}
|
||||
</Typography>
|
||||
</Box>
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<IconButton
|
||||
size="small"
|
||||
color="error"
|
||||
disabled={!selectedConversationId}
|
||||
onClick={(e) => this.handleDeleteConversation(e, selectedConversationId)}
|
||||
aria-label="Konversation löschen"
|
||||
sx={{
|
||||
borderRadius: 2,
|
||||
border: 1,
|
||||
borderColor: 'divider',
|
||||
p: 0.9,
|
||||
flexShrink: 0,
|
||||
}}
|
||||
>
|
||||
{conversations.map((c) => (
|
||||
<MenuItem key={c.id} value={c.id}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, width: '100%', overflow: 'hidden' }}>
|
||||
<Typography variant="body2" fontWeight={600} noWrap>
|
||||
#{c.id}
|
||||
</Typography>
|
||||
<Typography variant="caption" color="text.secondary" noWrap sx={{ flexGrow: 1 }}>
|
||||
{c.model || 'Standard'}
|
||||
</Typography>
|
||||
</Box>
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<DeleteOutlineRoundedIcon fontSize="small" />
|
||||
</IconButton>
|
||||
|
||||
<IconButton
|
||||
size="small"
|
||||
color="error"
|
||||
disabled={!selectedConversationId}
|
||||
onClick={(e) => this.handleDeleteConversation(e, selectedConversationId)}
|
||||
aria-label="Konversation löschen"
|
||||
sx={{
|
||||
borderRadius: 2,
|
||||
border: 1,
|
||||
borderColor: 'divider',
|
||||
p: 0.9,
|
||||
flexShrink: 0,
|
||||
}}
|
||||
>
|
||||
<DeleteOutlineRoundedIcon fontSize="small" />
|
||||
</IconButton>
|
||||
|
||||
<IconButton
|
||||
size="small"
|
||||
color="primary"
|
||||
disabled={!selectedConversationId}
|
||||
onClick={this.handleNewChat}
|
||||
aria-label="Neuer Chat"
|
||||
sx={{
|
||||
borderRadius: 2,
|
||||
border: 1,
|
||||
borderColor: 'divider',
|
||||
p: 0.9,
|
||||
flexShrink: 0,
|
||||
}}
|
||||
>
|
||||
<AddRoundedIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</Box>
|
||||
<IconButton
|
||||
size="small"
|
||||
color="primary"
|
||||
disabled={!selectedConversationId}
|
||||
onClick={this.handleNewChat}
|
||||
aria-label="Neuer Chat"
|
||||
sx={{
|
||||
borderRadius: 2,
|
||||
border: 1,
|
||||
borderColor: 'divider',
|
||||
p: 0.9,
|
||||
flexShrink: 0,
|
||||
}}
|
||||
>
|
||||
<AddRoundedIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -362,7 +349,6 @@ export default class ChatDrawer extends PureComponent {
|
||||
messages,
|
||||
streamingText,
|
||||
loadingConversations,
|
||||
loadingMessages,
|
||||
model,
|
||||
} = this.state;
|
||||
|
||||
@@ -391,20 +377,7 @@ export default class ChatDrawer extends PureComponent {
|
||||
gap: 2,
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
width: 56,
|
||||
height: 56,
|
||||
borderRadius: '50%',
|
||||
bgcolor: 'primary.light',
|
||||
color: 'primary.main',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
<AutoAwesomeRoundedIcon sx={{ fontSize: 32 }} />
|
||||
</Box>
|
||||
<AutoAwesomeRoundedIcon sx={{ fontSize: 44, color: 'primary.main', opacity: 0.85 }} />
|
||||
<Typography variant="h6" fontWeight={700}>
|
||||
Willkommen im Chat
|
||||
</Typography>
|
||||
|
||||
@@ -177,14 +177,17 @@ function MessageRow({ msg, showTime = true }) {
|
||||
bodyLength = textContent.length;
|
||||
}
|
||||
|
||||
let displayText = '';
|
||||
if (resObj && ('answer' in resObj || 'content' in resObj) && ('tool_call_id' in resObj) && !('status' in resObj)) {
|
||||
displayText = resObj.answer || resObj.content || '';
|
||||
} else {
|
||||
displayText = statusText
|
||||
const isToolAnswer =
|
||||
Boolean(resObj) &&
|
||||
('answer' in resObj || 'content' in resObj) &&
|
||||
'tool_call_id' in resObj &&
|
||||
!('status' in resObj);
|
||||
|
||||
const displayText = isToolAnswer
|
||||
? resObj.answer || resObj.content || ''
|
||||
: statusText
|
||||
? `${statusText}${bodyLength != null ? ` · ${bodyLength} byte` : ''}`
|
||||
: (bodyLength != null ? `${bodyLength} byte` : String(textContent));
|
||||
}
|
||||
|
||||
return (
|
||||
<Box sx={{ display: 'flex', justifyContent: 'flex-start', py: 0.35, px: 2 }}>
|
||||
|
||||
@@ -68,7 +68,7 @@ export class Attachment extends PureComponent {
|
||||
}
|
||||
};
|
||||
|
||||
handleTileClick = (e) => {
|
||||
handleTileClick = () => {
|
||||
const { attachment, onClick } = this.props;
|
||||
if (onClick && attachment) {
|
||||
onClick(attachment);
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
import { PureComponent } from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import Button from '@mui/material/Button';
|
||||
import CircularProgress from '@mui/material/CircularProgress';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
import BackendError from '../BackendError';
|
||||
import { PageTitleRight } from '../PageLayout';
|
||||
import { PanelTile, PanelTileGrid } from 'dashgui/panels';
|
||||
import { PanelTileGrid } from 'dashgui/panels';
|
||||
import { StorageManagerContext } from '../../api/storageManagerContext';
|
||||
import { requireArray, requireDefined, requireObject } from '../../utils/apiShape';
|
||||
import { backendErrorFrom } from '../../utils/backendError';
|
||||
@@ -435,7 +432,7 @@ class ManifestForm extends PureComponent {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { kind, mode } = this.props;
|
||||
const { kind } = this.props;
|
||||
const cfg = this.cfg;
|
||||
const {
|
||||
status,
|
||||
|
||||
@@ -85,7 +85,6 @@ class ManifestHeader extends PureComponent {
|
||||
saving,
|
||||
pdfUploading,
|
||||
attachments,
|
||||
lines,
|
||||
onPdfUpload,
|
||||
onPdfRescan,
|
||||
onPdfDelete,
|
||||
|
||||
@@ -24,7 +24,6 @@ class ManifestLines extends PureComponent {
|
||||
onAddLine,
|
||||
onRemoveLine,
|
||||
onRemoveAllLines,
|
||||
onSave,
|
||||
columns = LINE_COLUMNS,
|
||||
supplierArticlesMap = {},
|
||||
supplierArticlesByLineKey = {},
|
||||
|
||||
@@ -275,31 +275,6 @@ function fileToBase64(file) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert base64 string to Blob
|
||||
* @param {string} base64
|
||||
* @param {string} mimeType
|
||||
* @returns {Blob}
|
||||
*/
|
||||
function base64ToBlob(base64, mimeType) {
|
||||
const clean = base64.includes(',') ? base64.split(',')[1] : base64;
|
||||
const byteCharacters = atob(clean);
|
||||
const byteArrays = [];
|
||||
const sliceSize = 512;
|
||||
|
||||
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
|
||||
const slice = byteCharacters.slice(offset, offset + sliceSize);
|
||||
const byteNumbers = new Array(slice.length);
|
||||
for (let i = 0; i < slice.length; i++) {
|
||||
byteNumbers[i] = byteCharacters.charCodeAt(i);
|
||||
}
|
||||
const byteArray = new Uint8Array(byteNumbers);
|
||||
byteArrays.push(byteArray);
|
||||
}
|
||||
|
||||
return new Blob(byteArrays, { type: mimeType });
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore attachments from API response
|
||||
* @param {Array<{id: number, fileId?: number, manifestId?: number, mimetype: string, name: string, thumbavif?: any, size: number, created?: string, meta?: object}>} apiFiles
|
||||
|
||||
@@ -105,7 +105,7 @@ class KundeListePage extends PureComponent {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { status, error, entities, groupsById, busyId } = this.state;
|
||||
const { status, error, entities, busyId } = this.state;
|
||||
|
||||
if (status === 'failed') {
|
||||
return <BackendError error={error} onRetry={this.handleRetry} />;
|
||||
|
||||
@@ -21,7 +21,6 @@ import { enqueueSnackbar } from 'notistack';
|
||||
import { PanelTile, PanelTileGrid } from 'dashgui/panels';
|
||||
import BackendError from '../../components/BackendError';
|
||||
import withNavigate from '../../components/withNavigate';
|
||||
import { PageTitleRight } from '../../components/PageLayout';
|
||||
import {
|
||||
ManifestHeader,
|
||||
ManifestLines,
|
||||
|
||||
@@ -16,10 +16,7 @@
|
||||
* only as a de-duplication / reference key, not as the SKU.
|
||||
*/
|
||||
|
||||
import {
|
||||
parseImportCsv,
|
||||
parseCategoryPath,
|
||||
} from './importArtikelCsv';
|
||||
import { parseImportCsv } from './importArtikelCsv';
|
||||
import { article, category, brand } from '../api';
|
||||
import {
|
||||
requireObject,
|
||||
@@ -27,7 +24,6 @@ import {
|
||||
} from './apiShape';
|
||||
|
||||
function logImport(message) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`[import] ${message}`);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user