"use client"; import { Lock, RefreshCw } from "lucide-react"; import { Alert, AlertDescription, AlertTitle, Badge, Button, Label, } from "@/components/shadcn"; import { MultiSelect, MultiSelectContent, MultiSelectItem, MultiSelectTrigger, MultiSelectValue, } from "@/components/shadcn/select/multiselect"; import type { SlackChannelOption } from "@/types/integrations"; const INVITE_HINT = "A private channel only appears here after someone invites @Prowler to it in Slack. Invite it, then refresh."; interface SlackChannelMultiSelectProps { options: SlackChannelOption[]; values: string[]; onChange: (channelIds: string[]) => void; isLoading?: boolean; /** Why the channels could not be read — Slack's own reason, when it gave one. */ error?: string | null; /** Why the list is partial. Shown with the picker, not instead of it. */ incompleteNotice?: string | null; onRefresh?: () => void; disabled?: boolean; id?: string; /** Element explaining the picker — a caller's reason for disabling it. */ describedBy?: string; } const chipLabel = (option: SlackChannelOption) => ( {option.is_private && ( <> ); /** Driven entirely by props (design D1) so any consumer can reuse it. */ export const SlackChannelMultiSelect = ({ options, values, onChange, isLoading = false, error = null, incompleteNotice = null, onRefresh, disabled = false, id = "slack-channels", describedBy, }: SlackChannelMultiSelectProps) => { const isEmpty = !isLoading && !error && options.length === 0; // `htmlFor` may only name an element that exists, and the trigger is only // rendered in the picker branch. const hasPicker = !error && !isEmpty; // A copy: the list belongs to the caller. Sorted here rather than upstream so // every consumer of the picker offers the same order. const listed = [...options].sort((left, right) => left.name.localeCompare(right.name, undefined, { sensitivity: "base", numeric: true, }), ); return (
{onRefresh && ( )}
{error ? ( Could not read the workspace's channels {error} ) : isEmpty ? ( No channels available yet Prowler cannot see a single channel in this workspace. Create a public channel, or invite @Prowler to a private one in Slack with /invite @Prowler, then refresh. ) : ( <> {incompleteNotice && ( Not every channel is listed {incompleteNotice} )} {listed.map((option) => ( #{option.name} {option.is_private && ( Private )} ))} )}

{INVITE_HINT}

); };