a lot of stuff
ci / docker (backend, backend/Dockerfile, backend) (push) Successful in 14m29s
ci / docker (frontend, frontend/Dockerfile, frontend) (push) Successful in 14m28s

This commit is contained in:
2025-10-16 00:38:03 +02:00
parent 5b420a6b62
commit aef34791f3
21 changed files with 2987 additions and 736 deletions
+49 -86
View File
@@ -3,60 +3,6 @@ import { resolveDocumentAssetUrl } from '../asset_manager';
import { getTagColorStyle } from '../utils/colors';
import { DownloadIcon, FolderIcon, EditIcon } from '../ui/icons';
const FilterBar = ({
query,
onQueryChange,
tags,
activeTagIds,
onToggleTag,
onClear,
hasFilters,
}) => (
<div className="filter-bar">
<input
type="search"
placeholder="Search documents"
value={query}
onChange={(event) => onQueryChange(event.target.value)}
/>
<div className="tag-filters">
{tags.length ? (
tags.map((tag) => {
const isActive = activeTagIds.includes(tag.id);
const style = getTagColorStyle(tag.color);
const buttonStyle = style
? {
...style,
opacity: isActive ? 1 : 0.95,
boxShadow: isActive ? '0 0 0 1px var(--shadow-soft)' : undefined,
}
: undefined;
return (
<button
key={tag.id}
type="button"
className={`tag-filter${isActive ? ' active' : ''}`}
onClick={() => onToggleTag(tag.id)}
style={buttonStyle}
>
{tag.label}
</button>
);
})
) : (
<span className="meta">No tags yet</span>
)}
</div>
<div className="filter-actions">
{hasFilters && (
<button type="button" className="secondary" onClick={onClear}>
Clear
</button>
)}
</div>
</div>
);
const DocumentThumbnailImage = ({ document, ensureAssetUrl, getDocumentAsset, alt }) => {
const url = useMemo(
() =>
@@ -103,6 +49,8 @@ const DocumentsTable = ({
onFolderDragEnd,
draggedFolderId,
onFolderDelete,
selectedFolderIds = [],
onFolderRowClick,
onDocumentRowClick,
onDocumentOpen,
selectedDocumentIds,
@@ -114,7 +62,6 @@ const DocumentsTable = ({
onDocumentDelete,
onFolderRename,
onDocumentRename,
filterBar,
tagLookupById,
onDocumentListFocus,
onDocumentListKeyDown,
@@ -131,6 +78,10 @@ const DocumentsTable = ({
() => new Set(selectedDocumentIds),
[selectedDocumentIds],
);
const selectedFolderSet = useMemo(
() => new Set(selectedFolderIds || []),
[selectedFolderIds],
);
const draggingSet = useMemo(
() => new Set(draggingDocumentIds || []),
[draggingDocumentIds],
@@ -235,7 +186,6 @@ const DocumentsTable = ({
</div>
</div>
<div className="column-body">
<div className="column-toolbar">{filterBar}</div>
<div
ref={scrollRef}
className="documents-scroll"
@@ -275,20 +225,33 @@ const DocumentsTable = ({
subfolders.map((folder) => {
const canDragFolder = folder.id !== 'root';
const isDraggingFolder = draggedFolderId === folder.id;
const isSelectedFolder = selectedFolderSet.has(folder.id);
return (
<tr
key={folder.id}
className={`folder${isDraggingFolder ? ' is-dragging' : ''}${
focusedRowKey === `folder:${folder.id}` ? ' focused' : ''
}`}
}${isSelectedFolder ? ' selected' : ''}`}
id={`folder-row-${folder.id}`}
onClick={() => {
onFolderSelect(folder.id);
onClick={(event) => {
onFolderRowClick?.(folder.id, event);
const shouldNavigate =
!event.defaultPrevented &&
!event.metaKey &&
!event.ctrlKey &&
!event.shiftKey;
if (shouldNavigate) {
onFolderSelect(folder.id);
}
if (scrollRef.current) {
scrollRef.current.focus({ preventScroll: true });
}
onFocusedRowChange?.(`folder:${folder.id}`);
}}
onDoubleClick={(event) => {
event.preventDefault();
onFolderSelect(folder.id);
}}
onDragOver={(event) => onFolderDragOver(event, folder.id)}
onDragLeave={onFolderDragLeave}
onDrop={(event) => onFolderDrop(event, folder.id)}
@@ -413,36 +376,36 @@ const DocumentsTable = ({
{(doc.tags || []).length > 0 && (
<div className="doc-name__tags">
{(doc.tags || []).map((tag) => {
const colorSource = tag?.color || tagLookupById?.get(tag.id)?.color;
const style = getTagColorStyle(colorSource);
return (
<span
key={tag.id}
className="badge tag-chip"
style={style || undefined}
title={tag.label}
onClick={(event) => {
event.stopPropagation();
if (onTagClick) {
onTagClick(tag.id);
}
}}
role="button"
tabIndex={0}
onKeyDown={(event) => {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
const colorSource = tag?.color || tagLookupById?.get(tag.id)?.color;
const style = getTagColorStyle(colorSource);
return (
<span
key={tag.id}
className="badge tag-chip"
style={style || undefined}
title={tag.label}
onClick={(event) => {
event.stopPropagation();
if (onTagClick) {
onTagClick(tag.id);
}
}
}}
>
{tag.label}
</span>
);
})}
}}
role="button"
tabIndex={0}
onKeyDown={(event) => {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
event.stopPropagation();
if (onTagClick) {
onTagClick(tag.id);
}
}
}}
>
{tag.label}
</span>
);
})}
</div>
)}
</div>
@@ -504,4 +467,4 @@ const DocumentsTable = ({
};
export default DocumentsTable;
export { FilterBar, DocumentThumbnailImage };
export { DocumentThumbnailImage };