Skip to content

Commit 0f6fcb6

Browse files
committed
fix: pr comments
1 parent e96f63c commit 0f6fcb6

3 files changed

Lines changed: 61 additions & 66 deletions

File tree

packages/dashboard/src/lib/components/shared/assign-to-channel-dialog.tsx

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { toast } from '@/vdb/components/ui/sonner.js';
2-
import { ReactNode, useEffect, useMemo, useState } from 'react';
2+
import { ReactNode, useEffect, useState } from 'react';
33

4+
import { ChannelCodeLabel } from '@/vdb/components/shared/channel-code-label.js';
45
import { MultiSelect } from '@/vdb/components/shared/multi-select.js';
56
import { Button } from '@/vdb/components/ui/button.js';
67
import {
@@ -63,19 +64,13 @@ export function AssignToChannelDialog({
6364
}, [open]);
6465

6566
// Filter out the currently selected channel from available options
66-
const availableChannels = useMemo(
67-
() => channels.filter(channel => channel.id !== activeChannel?.id),
68-
[channels, activeChannel?.id],
69-
);
67+
const availableChannels = channels.filter(channel => channel.id !== activeChannel?.id);
7068

71-
const selectItems = useMemo(
72-
() =>
73-
availableChannels.map(ch => ({
74-
value: ch.id,
75-
label: ch.code,
76-
})),
77-
[availableChannels],
78-
);
69+
const selectItems = availableChannels.map(ch => ({
70+
value: ch.id,
71+
label: ch.code,
72+
display: <ChannelCodeLabel code={ch.code} />,
73+
}));
7974

8075
const handleAssign = async () => {
8176
setIsAssigning(true);
@@ -86,19 +81,28 @@ export function AssignToChannelDialog({
8681
),
8782
);
8883

89-
const rejected = results.filter(r => r.status === 'rejected');
90-
if (rejected.length === 0) {
84+
const failedChannelIds = results.flatMap((r, i) =>
85+
r.status === 'rejected' ? [selectedChannelIds[i]] : [],
86+
);
87+
const succeededCount = results.length - failedChannelIds.length;
88+
89+
if (succeededCount > 0) {
90+
onSuccess?.();
91+
}
92+
93+
if (failedChannelIds.length === 0) {
9194
toast.success(
9295
t`Successfully assigned ${entityIdsLength} ${entityType} to ${selectedChannelIds.length} channels`,
9396
);
94-
onSuccess?.();
9597
onOpenChange(false);
9698
} else {
97-
const firstReason = rejected[0]?.status === 'rejected' ? rejected[0].reason : undefined;
99+
const firstRejected = results.find(r => r.status === 'rejected');
100+
const firstReason = firstRejected?.status === 'rejected' ? firstRejected.reason : undefined;
98101
const description = firstReason instanceof Error ? firstReason.message : undefined;
102+
setSelectedChannelIds(failedChannelIds);
99103
toast.error(
100-
t`Failed to assign ${entityIdsLength} ${entityType} to ${rejected.length} of ${selectedChannelIds.length} channels`,
101-
description ? { description } : undefined,
104+
t`Failed to assign ${entityIdsLength} ${entityType} to ${failedChannelIds.length} of ${selectedChannelIds.length} channels`,
105+
{ description },
102106
);
103107
}
104108
} finally {

packages/dashboard/src/lib/components/shared/multi-select.tsx

Lines changed: 31 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { Badge } from '@/vdb/components/ui/badge.js';
22
import { Button } from '@/vdb/components/ui/button.js';
33
import { Popover, PopoverContent, PopoverTrigger } from '@/vdb/components/ui/popover.js';
44
import { cn } from '@/vdb/lib/utils.js';
5-
import { Popover as PopoverPrimitive } from '@base-ui/react/popover';
65
import { ChevronDown, X } from 'lucide-react';
76
import { useState } from 'react';
87
import { Input } from '../ui/input.js';
@@ -132,40 +131,38 @@ export function MultiSelect<T extends boolean>(props: MultiSelectProps<T>) {
132131
return (
133132
<Popover>
134133
<PopoverTrigger render={renderTrigger()}></PopoverTrigger>
135-
<PopoverPrimitive.Portal>
136-
<PopoverContent
137-
className="w-[200px] p-0"
138-
side="bottom"
139-
align="start"
140-
onWheel={e => e.stopPropagation()}
141-
>
142-
{(showSearch === true || items.length > 10) && (
143-
<div className="p-2">
144-
<Input
145-
type="text"
146-
placeholder={searchPlaceholder}
147-
value={search}
148-
onChange={e => setSearch(e.target.value)}
149-
className="w-full px-2 py-1 text-sm border rounded"
150-
/>
151-
</div>
152-
)}
153-
<div className="max-h-[300px] overflow-auto">
154-
{filteredItems.map(item => (
155-
<button
156-
key={item.value}
157-
onClick={() => handleSelect(item.value)}
158-
className={cn(
159-
'w-full px-2 py-1.5 text-sm text-left hover:bg-accent',
160-
multiple && (value as string[]).includes(item.value) && 'bg-accent',
161-
)}
162-
>
163-
{item.display ?? item.label}
164-
</button>
165-
))}
134+
<PopoverContent
135+
className="w-[200px] p-0"
136+
side="bottom"
137+
align="start"
138+
onWheel={e => e.stopPropagation()}
139+
>
140+
{(showSearch === true || items.length > 10) && (
141+
<div className="p-2">
142+
<Input
143+
type="text"
144+
placeholder={searchPlaceholder}
145+
value={search}
146+
onChange={e => setSearch(e.target.value)}
147+
className="w-full px-2 py-1 text-sm border rounded"
148+
/>
166149
</div>
167-
</PopoverContent>
168-
</PopoverPrimitive.Portal>
150+
)}
151+
<div className="max-h-[300px] overflow-auto">
152+
{filteredItems.map(item => (
153+
<button
154+
key={item.value}
155+
onClick={() => handleSelect(item.value)}
156+
className={cn(
157+
'w-full px-2 py-1.5 text-sm text-left hover:bg-accent',
158+
multiple && (value as string[]).includes(item.value) && 'bg-accent',
159+
)}
160+
>
161+
{item.display ?? item.label}
162+
</button>
163+
))}
164+
</div>
165+
</PopoverContent>
169166
</Popover>
170167
);
171168
}

0 commit comments

Comments
 (0)