added dateien page

This commit is contained in:
Ida Dittrich 2025-08-12 12:54:18 +02:00
parent 7cbdb0aea5
commit 10c7073cce
8 changed files with 141 additions and 66 deletions

View file

@ -49,6 +49,7 @@ function App() {
<Home />
</ProtectedRoute>
}>
<Route index element={<Dashboard />} />
<Route path="dashboard" element={<Dashboard />} />
<Route path="dateien" element={<Dateien />} />
<Route path="team-bereich" element={<TeamBereich />} />

View file

@ -128,7 +128,7 @@ export function useDateienLogic(): DateienLogicReturn {
const columns: ColumnConfig[] = useMemo(() => [
{
key: 'file_name',
label: 'Filename',
label: t('files.column.filename'),
type: 'string',
width: 300,
minWidth: 200,
@ -144,8 +144,7 @@ export function useDateienLogic(): DateienLogicReturn {
display: 'block',
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
paddingLeft: '8px'
textOverflow: 'ellipsis'
}}
title={value}
>
@ -155,7 +154,7 @@ export function useDateienLogic(): DateienLogicReturn {
},
{
key: 'mime_type',
label: 'mime type',
label: t('files.column.mimetype'),
type: 'string',
width: 200,
minWidth: 150,
@ -166,7 +165,7 @@ export function useDateienLogic(): DateienLogicReturn {
},
{
key: 'size',
label: 'filesize',
label: t('files.column.filesize'),
type: 'number',
width: 140,
minWidth: 120,
@ -181,7 +180,7 @@ export function useDateienLogic(): DateienLogicReturn {
},
{
key: 'created_at',
label: 'creation date',
label: t('files.column.creationdate'),
type: 'date',
width: 200,
minWidth: 180,
@ -190,7 +189,7 @@ export function useDateienLogic(): DateienLogicReturn {
filterable: true,
formatter: (value: string | undefined) => formatDate(value)
},
], []);
], [t]);
// Handle file download
const handleDownload = async (file: UserFile) => {

View file

@ -397,7 +397,7 @@ tbody .actionsColumn {
/* Pagination */
.pagination {
display: flex;
justify-content: center;
justify-content: space-between;
align-items: center;
gap: 10px;
padding: 15px;
@ -406,6 +406,37 @@ tbody .actionsColumn {
border-radius: 0 0 8px 8px;
}
.pageSizeSelector {
display: flex;
align-items: center;
gap: 8px;
font-size: 14px;
color: var(--color-text);
}
.pageSizeSelector label {
white-space: nowrap;
font-family: var(--font-family);
}
.pageSizeSelect {
height: 32px;
padding: 4px 8px;
border: 1px solid var(--color-primary);
border-radius: 4px;
font-size: 14px;
font-family: var(--font-family);
background: var(--color-bg);
color: var(--color-text);
cursor: pointer;
min-width: 60px;
}
.pageSizeSelect:focus {
outline: none;
border-color: var(--color-secondary);
}
.paginationButton {
padding: 8px 12px;
border: 1px solid var(--color-gray-disabled);
@ -490,16 +521,19 @@ tbody .actionsColumn {
}
.pagination {
flex-wrap: wrap;
gap: 5px;
flex-direction: column;
gap: 10px;
padding: 10px;
}
.paginationInfo {
.pageSizeSelector {
order: -1;
width: 100%;
justify-content: center;
}
.paginationInfo {
text-align: center;
margin: 0 0 10px 0;
margin: 0;
font-size: 13px;
}
}

View file

@ -27,6 +27,8 @@ export interface FormGeneratorProps<T = any> {
resizable?: boolean;
pagination?: boolean;
pageSize?: number;
pageSizeOptions?: number[];
showPageSizeSelector?: boolean;
onRowClick?: (row: T, index: number) => void;
onRowSelect?: (selectedRows: T[]) => void;
selectable?: boolean;
@ -49,6 +51,8 @@ export function FormGenerator<T extends Record<string, any>>({
resizable = true,
pagination = true,
pageSize = 10,
pageSizeOptions = [10, 25, 50, 100],
showPageSizeSelector = true,
onRowClick,
onRowSelect,
selectable = false,
@ -100,6 +104,7 @@ export function FormGenerator<T extends Record<string, any>>({
const [columnWidths, setColumnWidths] = useState<Record<string, number>>({});
const [selectedRows, setSelectedRows] = useState<Set<number>>(new Set());
const [currentPage, setCurrentPage] = useState(1);
const [currentPageSize, setCurrentPageSize] = useState(pageSize);
// Refs for resizing
const tableRef = useRef<HTMLTableElement>(null);
@ -188,11 +193,11 @@ export function FormGenerator<T extends Record<string, any>>({
const paginatedData = useMemo(() => {
if (!pagination) return filteredData;
const startIndex = (currentPage - 1) * pageSize;
return filteredData.slice(startIndex, startIndex + pageSize);
}, [filteredData, currentPage, pageSize, pagination]);
const startIndex = (currentPage - 1) * currentPageSize;
return filteredData.slice(startIndex, startIndex + currentPageSize);
}, [filteredData, currentPage, currentPageSize, pagination]);
const totalPages = Math.ceil(filteredData.length / pageSize);
const totalPages = Math.ceil(filteredData.length / currentPageSize);
// Handle sorting
const handleSort = (key: string) => {
@ -257,6 +262,12 @@ export function FormGenerator<T extends Record<string, any>>({
}
};
// Handle page size change
const handlePageSizeChange = (newPageSize: number) => {
setCurrentPageSize(newPageSize);
setCurrentPage(1); // Reset to first page when page size changes
};
// Handle column resizing
const handleMouseDown = (e: React.MouseEvent, columnKey: string) => {
if (!resizable) return;
@ -333,6 +344,7 @@ export function FormGenerator<T extends Record<string, any>>({
return (
<div className={`${styles.formGenerator} ${className}`}>
{title && <h2 className={styles.title}>{title}</h2>}
{(searchable || filterable) && (
@ -640,48 +652,68 @@ export function FormGenerator<T extends Record<string, any>>({
</div>
{/* Pagination */}
{pagination && totalPages > 1 && (
{pagination && (
<div className={styles.pagination}>
<button
onClick={() => setCurrentPage(1)}
disabled={currentPage === 1}
className={styles.paginationButton}
title={t('formgen.pagination.first')}
>
««
</button>
<button
onClick={() => setCurrentPage(currentPage - 1)}
disabled={currentPage === 1}
className={styles.paginationButton}
title={t('formgen.pagination.prev')}
>
«
</button>
{showPageSizeSelector && (
<div className={styles.pageSizeSelector}>
<label htmlFor="pageSize">{t('formgen.pagination.pageSize', 'Items per page:')}</label>
<select
id="pageSize"
value={currentPageSize}
onChange={(e) => handlePageSizeChange(Number(e.target.value))}
className={styles.pageSizeSelect}
>
{pageSizeOptions.map(size => (
<option key={size} value={size}>{size}</option>
))}
</select>
</div>
)}
<span className={styles.paginationInfo}>
{t('formgen.pagination.info')
.replace('{page}', currentPage.toString())
.replace('{total}', totalPages.toString())
.replace('{count}', filteredData.length.toString())}
</span>
<button
onClick={() => setCurrentPage(currentPage + 1)}
disabled={currentPage === totalPages}
className={styles.paginationButton}
title={t('formgen.pagination.next')}
>
»
</button>
<button
onClick={() => setCurrentPage(totalPages)}
disabled={currentPage === totalPages}
className={styles.paginationButton}
title={t('formgen.pagination.last')}
>
»»
</button>
{totalPages > 1 && (
<>
<button
onClick={() => setCurrentPage(1)}
disabled={currentPage === 1}
className={styles.paginationButton}
title={t('formgen.pagination.first')}
>
««
</button>
<button
onClick={() => setCurrentPage(currentPage - 1)}
disabled={currentPage === 1}
className={styles.paginationButton}
title={t('formgen.pagination.prev')}
>
«
</button>
<span className={styles.paginationInfo}>
{t('formgen.pagination.info')
.replace('{page}', currentPage.toString())
.replace('{total}', totalPages.toString())
.replace('{count}', filteredData.length.toString())}
</span>
<button
onClick={() => setCurrentPage(currentPage + 1)}
disabled={currentPage === totalPages}
className={styles.paginationButton}
title={t('formgen.pagination.next')}
>
»
</button>
<button
onClick={() => setCurrentPage(totalPages)}
disabled={currentPage === totalPages}
className={styles.paginationButton}
title={t('formgen.pagination.last')}
>
»»
</button>
</>
)}
</div>
)}
</div>

View file

@ -267,9 +267,13 @@ export default {
// File Table Columns
'files.column.name': 'Name',
'files.column.filename': 'Dateiname',
'files.column.type': 'Typ',
'files.column.mimetype': 'MIME-Typ',
'files.column.size': 'Größe',
'files.column.filesize': 'Dateigröße',
'files.column.created': 'Erstellt',
'files.column.creationdate': 'Erstellungsdatum',
'files.column.source': 'Quelle',
// File Types
@ -334,6 +338,7 @@ export default {
'formgen.filter.placeholder': '{column} filtern',
'formgen.actions.column': 'Aktionen',
'formgen.pagination.info': 'Seite {page} von {total} ({count} Einträge)',
'formgen.pagination.pageSize': 'Einträge pro Seite:',
'formgen.pagination.first': 'Erste Seite',
'formgen.pagination.prev': 'Vorherige Seite',
'formgen.pagination.next': 'Nächste Seite',

View file

@ -268,9 +268,13 @@ export default {
// File Table Columns
'files.column.name': 'Name',
'files.column.filename': 'Filename',
'files.column.type': 'Type',
'files.column.mimetype': 'MIME Type',
'files.column.size': 'Size',
'files.column.filesize': 'File Size',
'files.column.created': 'Created',
'files.column.creationdate': 'Creation Date',
'files.column.source': 'Source',
// File Types
@ -335,6 +339,7 @@ export default {
'formgen.filter.placeholder': 'Filter {column}',
'formgen.actions.column': 'Actions',
'formgen.pagination.info': 'Page {page} of {total} ({count} items)',
'formgen.pagination.pageSize': 'Items per page:',
'formgen.pagination.first': 'First page',
'formgen.pagination.prev': 'Previous page',
'formgen.pagination.next': 'Next page',

View file

@ -267,9 +267,13 @@ export default {
// File Table Columns
'files.column.name': 'Nom',
'files.column.filename': 'Nom de fichier',
'files.column.type': 'Type',
'files.column.mimetype': 'Type MIME',
'files.column.size': 'Taille',
'files.column.filesize': 'Taille du fichier',
'files.column.created': 'Créé',
'files.column.creationdate': 'Date de création',
'files.column.source': 'Source',
// File Types
@ -334,6 +338,7 @@ export default {
'formgen.filter.placeholder': 'Filtrer {column}',
'formgen.actions.column': 'Actions',
'formgen.pagination.info': 'Page {page} sur {total} ({count} éléments)',
'formgen.pagination.pageSize': 'Éléments par page:',
'formgen.pagination.first': 'Première page',
'formgen.pagination.prev': 'Page précédente',
'formgen.pagination.next': 'Page suivante',

View file

@ -7,6 +7,8 @@ function Dashboard () {
const [isChatExpanded, setIsChatExpanded] = useState(false);
const [selectedPrompt, setSelectedPrompt] = useState<Prompt | null>(null);
const [isPromptAreaCollapsed, setIsPromptAreaCollapsed] = useState(false);
const [currentWorkflowId, setCurrentWorkflowId] = useState<string | null>(null);
const [workflowCompleted, setWorkflowCompleted] = useState(false);
const handleChatToggleExpand = () => {
setIsChatExpanded(!isChatExpanded);
@ -25,7 +27,7 @@ function Dashboard () {
}
return workflowId;
});
}, []);
}, [setCurrentWorkflowId, setWorkflowCompleted]);
const handleWorkflowCompletedChange = useCallback((completed: boolean) => {
setWorkflowCompleted(completed);
@ -62,11 +64,3 @@ function Dashboard () {
}
export default Dashboard;
function setCurrentWorkflowId(arg0: (prevId: any) => string | null) {
throw new Error('Function not implemented.');
}
function setWorkflowCompleted(arg0: boolean) {
throw new Error('Function not implemented.');
}