"use client"; import { RefreshCw } from "lucide-react"; import { SlackInlineCode } from "@/components/integrations/slack/slack-inline-code"; import { Alert, AlertDescription, AlertTitle, Badge, Button, Label, } from "@/components/shadcn"; import { CustomLink } from "@/components/shadcn/custom/custom-link"; import { MultiSelect, MultiSelectContent, MultiSelectItem, MultiSelectTrigger, MultiSelectValue, } from "@/components/shadcn/select/multiselect"; import { DOCS_URLS } from "@/lib/external-urls"; import type { SlackChannelOption } from "@/types/integrations"; const INVITE_HINT = ( <> A private channel only appears here after someone invites{" "} @Prowler Cloud to it in Slack. Invite it, then refresh.{" "} Learn more ); 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; } /** Marked exactly as the listing marks it, so the chip is the row it came from. */ const chipLabel = (option: SlackChannelOption) => ( #{option.name} {option.is_private && ( 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 Cloud to a private one in Slack with{" "} /invite @Prowler Cloud, then refresh. ) : ( <> {incompleteNotice && ( Not every channel is listed {incompleteNotice} )} {listed.map((option) => ( #{option.name} {option.is_private && ( Private )} ))} )}

{INVITE_HINT}

); };