style
This commit is contained in:
@@ -26,6 +26,15 @@ The compose service uses tmpfs storage, giving each test run a clean database.
|
|||||||
- `ocrmypdf` (optional but recommended): Used by the OCR worker to extract text from PDFs when no embedded text layer is available. Ensure it is installed and available on the worker hosts if OCR is desired.
|
- `ocrmypdf` (optional but recommended): Used by the OCR worker to extract text from PDFs when no embedded text layer is available. Ensure it is installed and available on the worker hosts if OCR is desired.
|
||||||
- Quickwit (optional): The Quickwit indexer is used to ingest extracted text for search. Set `QUICKWIT_ENDPOINT` and `QUICKWIT_INDEX` in the environment when running workers if you want indexing jobs to run. The local compose file starts a Quickwit instance on `http://localhost:7280` and seeds the `documents` index automatically.
|
- Quickwit (optional): The Quickwit indexer is used to ingest extracted text for search. Set `QUICKWIT_ENDPOINT` and `QUICKWIT_INDEX` in the environment when running workers if you want indexing jobs to run. The local compose file starts a Quickwit instance on `http://localhost:7280` and seeds the `documents` index automatically.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
The backend reads its settings from environment variables (see `backend/.env` for local defaults). In particular:
|
||||||
|
|
||||||
|
- `DATABASE_URL` – connection string for the primary Postgres database (required).
|
||||||
|
- `DATABASE_MAX_POOL_SIZE` – optional override for the r2d2 connection pool size. Defaults to `2`; increase it in staging/production to match expected concurrency.
|
||||||
|
|
||||||
|
On startup each binary logs the effective configuration with secrets redacted (for example, the database password is masked). This makes it easier to confirm the runtime settings in staging without exposing credentials.
|
||||||
|
|
||||||
## Running Migrations in Kubernetes
|
## Running Migrations in Kubernetes
|
||||||
|
|
||||||
The backend container image ships the `diesel` CLI, so schema migrations can be executed as a short-lived Job (or Helm hook) before rolling out new pods. Example manifest:
|
The backend container image ships the `diesel` CLI, so schema migrations can be executed as a short-lived Job (or Helm hook) before rolling out new pods. Example manifest:
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ const DocumentsTable = ({
|
|||||||
onDocumentTagDrop,
|
onDocumentTagDrop,
|
||||||
viewMode = 'list',
|
viewMode = 'list',
|
||||||
onViewModeChange,
|
onViewModeChange,
|
||||||
|
onClearSelection,
|
||||||
}) => {
|
}) => {
|
||||||
const showingSearchResults = searchResults !== null;
|
const showingSearchResults = searchResults !== null;
|
||||||
const rows = showingSearchResults ? searchResults : documents;
|
const rows = showingSearchResults ? searchResults : documents;
|
||||||
@@ -213,6 +214,16 @@ const DocumentsTable = ({
|
|||||||
[isTagDragEvent, onDocumentTagDrop],
|
[isTagDragEvent, onDocumentTagDrop],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleGridBackgroundClick = useCallback(
|
||||||
|
(event) => {
|
||||||
|
if (event.target !== event.currentTarget) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
onClearSelection?.();
|
||||||
|
},
|
||||||
|
[onClearSelection],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section
|
<section
|
||||||
className={`documents-panel column documents-panel--view-${isGridView ? 'grid' : 'list'}`}
|
className={`documents-panel column documents-panel--view-${isGridView ? 'grid' : 'list'}`}
|
||||||
@@ -307,7 +318,11 @@ const DocumentsTable = ({
|
|||||||
Drop files anywhere or onto a folder to upload documents.
|
Drop files anywhere or onto a folder to upload documents.
|
||||||
</div>
|
</div>
|
||||||
) : isGridView ? (
|
) : isGridView ? (
|
||||||
<div className="documents-grid" role="list">
|
<div
|
||||||
|
className="documents-grid"
|
||||||
|
role="list"
|
||||||
|
onClick={handleGridBackgroundClick}
|
||||||
|
>
|
||||||
{!showingSearchResults &&
|
{!showingSearchResults &&
|
||||||
subfolders.map((folder) => {
|
subfolders.map((folder) => {
|
||||||
const canDragFolder = folder.id !== 'root';
|
const canDragFolder = folder.id !== 'root';
|
||||||
@@ -353,7 +368,7 @@ const DocumentsTable = ({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="folder-card__icon">
|
<div className="folder-card__icon">
|
||||||
<FolderIcon className="icon-inline" size={32} />
|
<FolderIcon className="folder-card__icon-svg" size={128} />
|
||||||
</div>
|
</div>
|
||||||
<div className="folder-card__meta">
|
<div className="folder-card__meta">
|
||||||
<div className="folder-card__name" title={folder.name}>
|
<div className="folder-card__name" title={folder.name}>
|
||||||
@@ -756,7 +771,7 @@ const DocumentsTable = ({
|
|||||||
)}
|
)}
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DocumentsTable;
|
export default DocumentsTable;
|
||||||
export { DocumentThumbnailImage };
|
export { DocumentThumbnailImage };
|
||||||
|
|||||||
@@ -1246,6 +1246,11 @@ const AppLayout = () => {
|
|||||||
[handleRowSelection],
|
[handleRowSelection],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const clearDocumentSelection = useCallback(() => {
|
||||||
|
setFocusedRowKey(null);
|
||||||
|
applySelection([], { anchor: null, interactedKeys: [] });
|
||||||
|
}, [applySelection]);
|
||||||
|
|
||||||
const handleFolderRowClick = useCallback(
|
const handleFolderRowClick = useCallback(
|
||||||
(folderId, event) => {
|
(folderId, event) => {
|
||||||
const rowKey = resolveFolderRowKey(folderId);
|
const rowKey = resolveFolderRowKey(folderId);
|
||||||
@@ -4522,6 +4527,7 @@ const AppLayout = () => {
|
|||||||
onDocumentTagDrop: handleDocumentTagDrop,
|
onDocumentTagDrop: handleDocumentTagDrop,
|
||||||
viewMode: documentsViewMode,
|
viewMode: documentsViewMode,
|
||||||
onViewModeChange: handleDocumentsViewModeChange,
|
onViewModeChange: handleDocumentsViewModeChange,
|
||||||
|
onClearSelection: clearDocumentSelection,
|
||||||
};
|
};
|
||||||
|
|
||||||
const detailPanelProps = {
|
const detailPanelProps = {
|
||||||
|
|||||||
+10
-14
@@ -1309,7 +1309,7 @@ button.icon-button.ghost:hover:not([disabled]) {
|
|||||||
.documents-grid {
|
.documents-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(128px, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(128px, 1fr));
|
||||||
gap: 0.2rem 1.3rem;
|
gap: 0.3rem 1.3rem;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1317,7 +1317,7 @@ button.icon-button.ghost:hover:not([disabled]) {
|
|||||||
padding: 0rem;
|
padding: 0rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 0.1rem;
|
gap: 0.3rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@@ -1364,6 +1364,7 @@ button.icon-button.ghost:hover:not([disabled]) {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 0.25rem;
|
gap: 0.25rem;
|
||||||
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.folder-card {
|
.folder-card {
|
||||||
@@ -1375,11 +1376,16 @@ button.icon-button.ghost:hover:not([disabled]) {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
width: 100%;
|
width: 128px;
|
||||||
aspect-ratio: 1;
|
height: 128px;
|
||||||
color: var(--accent);
|
color: var(--accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.folder-card__icon-svg {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.folder-card__meta {
|
.folder-card__meta {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -1396,16 +1402,6 @@ button.icon-button.ghost:hover:not([disabled]) {
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.folder-card__badge {
|
|
||||||
display: inline-flex;
|
|
||||||
align-self: center;
|
|
||||||
padding: 0.12rem 0.45rem;
|
|
||||||
font-size: 0.72rem;
|
|
||||||
border-radius: 999px;
|
|
||||||
background: var(--surface-soft);
|
|
||||||
color: var(--muted);
|
|
||||||
border: 1px solid var(--border);
|
|
||||||
}
|
|
||||||
|
|
||||||
.doc-name__title {
|
.doc-name__title {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
|||||||
Reference in New Issue
Block a user