mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-01-05 01:58:50 +01:00
feat: enhance DataTable with column pinning and improve sorting functionality
This commit is contained in:
parent
8b5f9104ef
commit
0c8598bd15
3 changed files with 298 additions and 100 deletions
|
|
@ -1,5 +1,4 @@
|
|||
import { useCallback, useState, useMemo } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { TrashIcon, MessageSquare } from 'lucide-react';
|
||||
import type { SharedLinkItem, SharedLinksListParams } from 'librechat-data-provider';
|
||||
|
|
@ -95,10 +94,6 @@ export default function SharedLinks() {
|
|||
);
|
||||
|
||||
if (validRows.length === 0) {
|
||||
showToast({
|
||||
message: localize('com_ui_no_valid_items'),
|
||||
severity: NotificationSeverity.WARNING,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -188,11 +183,7 @@ export default function SharedLinks() {
|
|||
},
|
||||
{
|
||||
accessorKey: 'actions',
|
||||
header: () => (
|
||||
<Label className="px-2 py-0 text-xs hover:bg-surface-hover sm:px-2 sm:py-2 sm:text-sm">
|
||||
{localize('com_assistants_actions')}
|
||||
</Label>
|
||||
),
|
||||
header: () => <Label>{localize('com_assistants_actions')}</Label>,
|
||||
meta: {
|
||||
size: '7%',
|
||||
mobileSize: '25%',
|
||||
|
|
@ -255,14 +246,25 @@ export default function SharedLinks() {
|
|||
columns={columns}
|
||||
data={allLinks}
|
||||
onDelete={handleDelete}
|
||||
config={{ skeleton: { count: 10 }, search: { filterColumn: 'title' } }}
|
||||
config={{
|
||||
skeleton: { count: 10 },
|
||||
search: {
|
||||
filterColumn: 'title',
|
||||
enableSearch: true,
|
||||
debounce: 300,
|
||||
},
|
||||
selection: {
|
||||
enableRowSelection: true,
|
||||
showCheckboxes: true,
|
||||
},
|
||||
}}
|
||||
hasNextPage={hasNextPage}
|
||||
isFetchingNextPage={isFetchingNextPage}
|
||||
isFetching={isFetching}
|
||||
fetchNextPage={handleFetchNextPage}
|
||||
onFilterChange={handleFilterChange}
|
||||
isLoading={isLoading}
|
||||
onSortChange={handleSort}
|
||||
onSortingChange={handleSort}
|
||||
sortBy={queryParams.sortBy}
|
||||
sortDirection={queryParams.sortDirection}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -27,12 +27,15 @@ import { NotificationSeverity } from '~/common';
|
|||
import { useLocalize } from '~/hooks';
|
||||
import { formatDate } from '~/utils';
|
||||
|
||||
const DEFAULT_PARAMS: ConversationListParams = {
|
||||
const DEFAULT_PARAMS = {
|
||||
isArchived: true,
|
||||
sortBy: 'createdAt',
|
||||
sortDirection: 'desc',
|
||||
search: '',
|
||||
};
|
||||
} as const satisfies ConversationListParams;
|
||||
|
||||
type SortKey = 'createdAt' | 'title';
|
||||
const isSortKey = (v: string): v is SortKey => v === 'createdAt' || v === 'title';
|
||||
|
||||
const defaultSort: SortingState = [
|
||||
{
|
||||
|
|
@ -42,6 +45,7 @@ const defaultSort: SortingState = [
|
|||
];
|
||||
|
||||
// Define the table column type for better type safety
|
||||
// (kept from your original code)
|
||||
type TableColumn<TData, TValue> = ColumnDef<TData, TValue> & {
|
||||
meta?: {
|
||||
size?: string | number;
|
||||
|
|
@ -82,26 +86,36 @@ export default function ArchivedChatsTable() {
|
|||
}));
|
||||
}, []);
|
||||
|
||||
// Robust against stale state; keeps UI sort in sync with backend defaults
|
||||
const handleSortingChange = useCallback(
|
||||
(updater: SortingState | ((old: SortingState) => SortingState)) => {
|
||||
const newSorting = typeof updater === 'function' ? updater(sorting) : updater;
|
||||
setSorting(newSorting);
|
||||
const sortDescriptor = newSorting[0];
|
||||
if (sortDescriptor) {
|
||||
setQueryParams((prev) => ({
|
||||
...prev,
|
||||
sortBy: sortDescriptor.id as 'createdAt' | 'title',
|
||||
sortDirection: sortDescriptor.desc ? 'desc' : 'asc',
|
||||
}));
|
||||
} else {
|
||||
setQueryParams((prev) => ({
|
||||
...prev,
|
||||
sortBy: 'createdAt',
|
||||
sortDirection: 'desc',
|
||||
}));
|
||||
}
|
||||
setSorting((prev) => {
|
||||
const next = typeof updater === 'function' ? updater(prev) : updater;
|
||||
|
||||
// If user clears sorting, fall back to default both in UI and query
|
||||
const coerced = next.length === 0 ? defaultSort : next;
|
||||
const primary = coerced[0];
|
||||
|
||||
setQueryParams((p) => {
|
||||
if (primary && isSortKey(primary.id)) {
|
||||
return {
|
||||
...p,
|
||||
sortBy: primary.id,
|
||||
sortDirection: primary.desc ? 'desc' : 'asc',
|
||||
};
|
||||
}
|
||||
// Fallback if id isn't one of the permitted keys
|
||||
return {
|
||||
...p,
|
||||
sortBy: 'createdAt',
|
||||
sortDirection: 'desc',
|
||||
};
|
||||
});
|
||||
|
||||
return coerced;
|
||||
});
|
||||
},
|
||||
[sorting],
|
||||
[setQueryParams, setSorting],
|
||||
);
|
||||
|
||||
const handleError = useCallback(
|
||||
|
|
@ -317,6 +331,29 @@ export default function ArchivedChatsTable() {
|
|||
/>
|
||||
</OGDialogContent>
|
||||
</OGDialog>
|
||||
<OGDialog open={isDeleteOpen} onOpenChange={setIsDeleteOpen}>
|
||||
<OGDialogTemplate
|
||||
showCloseButton={false}
|
||||
title={localize('com_ui_delete_archived_chats')}
|
||||
className="w-11/12 max-w-md"
|
||||
main={
|
||||
<div className="flex w-full flex-col items-center gap-2">
|
||||
<div className="grid w-full items-center gap-2">
|
||||
<Label className="text-left text-sm font-medium">
|
||||
{localize('com_ui_delete_confirm')} <strong>{deleteRow?.title}</strong>
|
||||
</Label>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
selection={{
|
||||
selectHandler: confirmDelete,
|
||||
selectClasses: `bg-red-700 dark:bg-red-600 hover:bg-red-800 dark:hover:bg-red-800 text-white ${
|
||||
deleteMutation.isLoading ? 'cursor-not-allowed opacity-80' : ''
|
||||
}`,
|
||||
selectText: deleteMutation.isLoading ? <Spinner /> : localize('com_ui_delete'),
|
||||
}}
|
||||
/>
|
||||
</OGDialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue