Implement collection suggestions and bulk show addition features
Added new API endpoints for suggesting collections based on existing shows and for bulk adding shows to collections. Enhanced the backend with necessary logic and DTOs to support these features. Updated the frontend to include new components for displaying collection suggestions and managing bulk additions, improving the user experience for collection management. Localization updates were made to support these new features in both English and Russian.
This commit is contained in:
@@ -149,6 +149,10 @@ export function GroupDetail({ groupId }: Readonly<{ groupId: string }>) {
|
||||
|
||||
const fresh = (candidates ?? []).filter((c) => !c.alreadyInGroup)
|
||||
const isDynamic = group.mode === 'Dynamic'
|
||||
// Закреплённое, которого черновик правила не находит, в составе всё равно останется.
|
||||
const pinnedNotMatched = group.items.filter(
|
||||
(i) => i.pinned && !(candidates ?? []).some((c) => c.elementId === i.elementId),
|
||||
).length
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-6">
|
||||
@@ -264,7 +268,16 @@ export function GroupDetail({ groupId }: Readonly<{ groupId: string }>) {
|
||||
>
|
||||
<Search className="h-4 w-4" /> {t('admin.groups.find')}
|
||||
</Button>
|
||||
{candidates !== null && (
|
||||
{candidates !== null && isDynamic && (
|
||||
// У группы по правилу «добавить найденное» не имеет смысла — правило и есть состав.
|
||||
// Показываем, каким станет состав, если сохранить черновик правила.
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{t('admin.groups.previewComposition', {
|
||||
count: candidates.length + pinnedNotMatched,
|
||||
})}
|
||||
</span>
|
||||
)}
|
||||
{candidates !== null && !isDynamic && (
|
||||
<>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{t('admin.groups.found', { total: candidates.length, fresh: fresh.length })}
|
||||
|
||||
@@ -17,6 +17,7 @@ export function GroupsPanel() {
|
||||
const { t } = useTranslation()
|
||||
const queryClient = useQueryClient()
|
||||
const [name, setName] = useState('')
|
||||
const [query, setQuery] = useState('')
|
||||
const { sort, toggle } = useTableSort('name', false)
|
||||
|
||||
const { data, isLoading } = useQuery({ queryKey: qk.groups.all, queryFn: listGroups })
|
||||
@@ -34,7 +35,11 @@ export function GroupsPanel() {
|
||||
})
|
||||
const deleteMutation = useMutation({ mutationFn: deleteGroup, onSuccess: invalidate, onError })
|
||||
|
||||
const rows = sortRows(data ?? [], sort, {
|
||||
const term = query.trim().toLowerCase()
|
||||
const matched = term
|
||||
? (data ?? []).filter((g) => g.name.toLowerCase().includes(term))
|
||||
: (data ?? [])
|
||||
const rows = sortRows(matched, sort, {
|
||||
name: (g) => g.name.toLowerCase(),
|
||||
items: (g) => g.itemCount,
|
||||
units: (g) => g.unitCount,
|
||||
@@ -64,6 +69,13 @@ export function GroupsPanel() {
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Input
|
||||
className="max-w-xs"
|
||||
placeholder={t('common.search')}
|
||||
value={query}
|
||||
onChange={(e) => setQuery(e.target.value)}
|
||||
/>
|
||||
|
||||
<GroupSuggestions />
|
||||
|
||||
<div className="crt-panel overflow-x-auto rounded-md">
|
||||
|
||||
Reference in New Issue
Block a user