frontend lint

This commit is contained in:
2025-10-29 17:40:11 +01:00
parent 1cc0aafc1a
commit ec6e7f04f2
10 changed files with 2655 additions and 319 deletions
+1 -248
View File
@@ -397,33 +397,6 @@ const DocumentsLayout = ({ sidebarProps, children, sidebarCollapsed }) => (
</main>
);
const MainContentShell = ({
className,
header = {},
sidebarToggleButton = null,
children,
}) => {
const { title = '', subtitle = null, leading = null, actions = null } = header || {};
return (
<div className={className}>
<div className="panel-header main-content__header">
<div className="panel-actions main-content__actions">
{sidebarToggleButton}
{leading}
<h2 className="main-content__title">
{title}
{subtitle ? <span className="main-content__subtitle">{subtitle}</span> : null}
</h2>
<div className="spacer" />
{actions}
</div>
</div>
{children}
</div>
);
};
const AppLayout = () => {
const navigate = useNavigate();
const location = useLocation();
@@ -445,9 +418,6 @@ const AppLayout = () => {
({ message, variant }) => setStatusMessage(message, variant),
[setStatusMessage],
);
const [sidebarCollapsed, setSidebarCollapsed] = useState(false);
const collapseSidebar = useCallback(() => setSidebarCollapsed(true), []);
const expandSidebar = useCallback(() => setSidebarCollapsed(false), []);
const reportApiError = useApiError({
onReport: handleApiReport,
});
@@ -616,12 +586,6 @@ const AppLayout = () => {
}
const tagManager = tagManagerRef.current;
const buildTagPayload = useCallback(
({ label, color } = {}) => tagManager.buildPayload({ label, color }),
[tagManager],
);
const getDocumentAsset = useCallback((doc, type) => {
if (!doc || !type) return null;
return getAssetFromVersion(doc.current_version || null, type);
@@ -1247,16 +1211,6 @@ const AppLayout = () => {
[selectedRowKeys, updateSelectionOrder],
);
const visibleSelectedCount = useMemo(
() => selectedDocumentIds.filter((id) => visibleDocumentIds.includes(id)).length,
[selectedDocumentIds, visibleDocumentIds],
);
const allDocumentsSelected =
visibleDocumentIds.length > 0 &&
visibleSelectedCount === visibleDocumentIds.length;
const someDocumentsSelected =
visibleSelectedCount > 0 && !allDocumentsSelected;
const folderOptions = useMemo(() => {
const cache = new Map();
@@ -2498,73 +2452,6 @@ const AppLayout = () => {
};
}, [appStatus, appDispatch, initializeAfterLogin]);
const handleBulkMoveSubmit = useCallback(
async (event) => {
event.preventDefault();
if (!selectedDocumentIds.length) {
setStatusMessage('Select documents before moving.', 'error');
return;
}
const form = new FormData(event.currentTarget);
const target = form.get('target')?.toString() || 'root';
const folderId = target === 'root' ? null : target;
if (!refreshOnly) {
setLoading(true);
}
try {
await api.post('/documents/bulk/move', {
document_ids: selectedDocumentIds,
folder_id: folderId,
});
const count = selectedDocumentIds.length;
const suffix = count === 1 ? '' : 's';
const folderLabel =
folderId === null
? DEFAULT_FOLDER_NAME
: folderLabelMap.get(target) || 'target folder';
setStatusMessage(
`Moved ${count} document${suffix} to ${folderLabel}.`,
'success',
);
applySelection([], { anchor: null });
await refreshCurrentFolder();
if (folderId && folderId !== selectedFolder) {
await ensureFolderData(folderId, { force: true, prefetchDepth: 1 });
}
event.currentTarget.reset();
} catch (error) {
const message = error.response?.data?.error || 'Failed to move documents.';
notifyApiError(error, message);
} finally {
setLoading(false);
}
},
[
api,
selectedDocumentIds,
folderLabelMap,
applySelection,
refreshCurrentFolder,
ensureFolderData,
notifyApiError,
selectedFolder,
setStatusMessage,
],
);
const parseTagInput = useCallback((value) => {
return value
.split(',')
.map((item) => item.trim())
.filter(Boolean);
}, []);
const bulkTagOperation = useCallback(
async ({ labels, action, documentIds }) => {
const normalized = labels.map((label) => label.trim()).filter((label) => label.length > 0);
@@ -2650,81 +2537,6 @@ const AppLayout = () => {
],
);
const handleBulkTagAdd = useCallback(
async (event) => {
event.preventDefault();
if (!selectedDocumentIds.length) {
setStatusMessage('Select documents before assigning tags.', 'error');
return;
}
const form = new FormData(event.currentTarget);
const raw = form.get('tags')?.toString().trim() || '';
const labels = parseTagInput(raw);
if (!labels.length) {
setStatusMessage('Enter at least one tag label.', 'error');
return;
}
const result = await bulkTagOperation({ labels, action: 'add' });
if (result?.ok) {
const { tagCount, docsCount } = result;
setStatusMessage(
`Assigned ${tagCount} tag${tagCount === 1 ? '' : 's'} to ${docsCount} document${
docsCount === 1 ? '' : 's'
}.`,
'success',
);
event.currentTarget.reset();
} else if (result?.reason === 'no-labels') {
setStatusMessage('Enter at least one tag label.', 'error');
}
},
[
selectedDocumentIds,
setStatusMessage,
parseTagInput,
bulkTagOperation,
],
);
const handleBulkTagRemove = useCallback(
async (event) => {
event.preventDefault();
if (!selectedDocumentIds.length) {
setStatusMessage('Select documents before removing tags.', 'error');
return;
}
const form = new FormData(event.currentTarget);
const raw = form.get('tags')?.toString().trim() || '';
const labels = parseTagInput(raw);
if (!labels.length) {
setStatusMessage('Enter at least one tag label to remove.', 'error');
return;
}
const result = await bulkTagOperation({ labels, action: 'remove' });
if (result?.ok) {
const { docsCount } = result;
setStatusMessage(
`Removed tags from ${docsCount} document${docsCount === 1 ? '' : 's'}.`,
'success',
);
event.currentTarget.reset();
} else if (result?.reason === 'no-labels') {
setStatusMessage('Enter at least one tag label to remove.', 'error');
} else if (result?.reason === 'tag-missing') {
setStatusMessage(`Tag “${result.label}” not found.`, 'error');
}
},
[
selectedDocumentIds,
setStatusMessage,
parseTagInput,
bulkTagOperation,
],
);
const handleBulkTagAddFromDetail = useCallback(
async ({ label, input, documentIds }) => {
const trimmed = (label || '').trim();
@@ -3371,7 +3183,7 @@ const AppLayout = () => {
}),
);
Array.from(dataTransfer.files || []).forEach((file, index) => {
Array.from(dataTransfer.files || []).forEach((file) => {
if (!file) return;
// FileList entry suppressed
const relativePath =
@@ -4554,54 +4366,6 @@ const AppLayout = () => {
};
}, [handleTagRemove, setTagRemovalCursor]);
const handleLogin = useCallback(
async (event) => {
event.preventDefault();
const form = new FormData(event.currentTarget);
const payload = {
username: form.get('username')?.toString().trim(),
password: form.get('password')?.toString() || '',
};
if (!payload.username || !payload.password) {
setStatusMessage('Username and password are required.', 'error');
return;
}
try {
setLoading(true);
appDispatch({ type: 'LOGIN_REQUEST' });
const { data } = await api.post('/auth/login', payload);
if (data?.access_token && Array.isArray(data?.tenants)) {
appDispatch({
type: 'TENANT_SELECTION_REQUIRED',
selectionToken: data.access_token,
tenants: data.tenants,
});
setStatusMessage('Select a tenant to continue.', 'info');
return;
}
if (!data?.access_token) {
throw new Error('Invalid login response.');
}
appDispatch({
type: 'LOGIN_SUCCESS',
token: data.access_token,
tenant: data.tenant || null,
});
setStatusMessage('Login successful.', 'success');
} catch (error) {
const message = error?.response?.data?.error || 'Login failed. Check credentials.';
appDispatch({ type: 'LOGIN_FAILURE', error: message });
notifyApiError(error, message);
} finally {
setLoading(false);
}
},
[appDispatch, notifyApiError, setStatusMessage],
);
const handleLogout = useCallback(async () => {
try {
setLoading(true);
@@ -5333,7 +5097,6 @@ const AppLayout = () => {
isFilterActive,
onLogout: handleLogout,
status,
onCollapse: collapseSidebar,
tenantSlug,
tenants: tenantOptions,
activeTenantId: currentTenantId,
@@ -5341,16 +5104,6 @@ const AppLayout = () => {
onOpenSettings: openSettingsModal,
};
const sidebarPropsWithActions = useMemo(
() => ({
...sidebarProps,
onManageTags: openTagsModal,
onManageCorrespondents: openCorrespondentsModal,
onCollapse: collapseSidebar,
}),
[sidebarProps, openTagsModal, openCorrespondentsModal, collapseSidebar],
);
const handleDetailPanelClose = useCallback(() => {
setDetailPanelOpen(false);
clearDocumentSelection();