{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "report-form",
  "title": "CodeRabbit Report Form",
  "author": "Ray <hello@ramonclaudio.com>",
  "description": "Full-featured form component for collecting report parameters. Includes template selection, custom prompts, filters, and grouping options.",
  "dependencies": [
    "react",
    "lucide-react"
  ],
  "registryDependencies": [
    "button",
    "input",
    "label",
    "select",
    "textarea",
    "https://coderabbit-shadcn-registry.vercel.app/r/types.json"
  ],
  "files": [
    {
      "path": "registry/default/components/report-form/report-form.tsx",
      "content": "'use client'\n\nimport { useState, useEffect, useRef } from 'react'\nimport { Plus, X } from 'lucide-react'\nimport { Label } from '@/components/ui/label'\nimport { Textarea } from '@/components/ui/textarea'\nimport { Input } from '@/components/ui/input'\nimport { Button } from '@/components/ui/button'\nimport {\n  Select,\n  SelectContent,\n  SelectItem,\n  SelectTrigger,\n  SelectValue,\n} from '@/components/ui/select'\nimport type {\n  PromptTemplate,\n  FilterParameter,\n  FilterOperator,\n  GroupBy,\n} from '@/registry/default/lib/types'\n\nconst PROMPT_TEMPLATES = [\n  'Select template',\n  'Daily Standup Report',\n  'Sprint Report',\n  'Release Notes',\n  'Custom',\n] as const\n\nconst GROUP_BY_OPTIONS = [\n  { value: 'NONE', label: 'None' },\n  { value: 'REPOSITORY', label: 'Repository' },\n  { value: 'USER', label: 'User' },\n  { value: 'TEAM', label: 'Team' },\n  { value: 'LABEL', label: 'Label' },\n  { value: 'STATE', label: 'State' },\n  { value: 'SOURCEBRANCH', label: 'Source Branch' },\n  { value: 'TARGETBRANCH', label: 'Target Branch' },\n] as const\n\nconst FILTER_PARAMETERS = [\n  { value: 'REPOSITORY', label: 'Repository' },\n  { value: 'LABEL', label: 'Label' },\n  { value: 'TEAM', label: 'Team' },\n  { value: 'USER', label: 'User' },\n  { value: 'SOURCEBRANCH', label: 'Source Branch' },\n  { value: 'TARGETBRANCH', label: 'Target Branch' },\n  { value: 'STATE', label: 'State' },\n] as const\n\nconst FILTER_OPERATORS = [\n  { value: 'IN', label: 'In' },\n  { value: 'ALL', label: 'All' },\n  { value: 'NOT_IN', label: 'Not In' },\n] as const\n\nexport interface FilterParameterForm {\n  parameter: string\n  operator: string\n  values: string\n}\n\nexport interface CodeRabbitReportFormData {\n  fromDate: string\n  toDate: string\n  promptTemplate: string\n  customPrompt: string\n  groupBy: string\n  subgroupBy: string\n  orgId: string\n  filters: FilterParameterForm[]\n}\n\ninterface CodeRabbitReportFormProps {\n  value: CodeRabbitReportFormData\n  onChange: (value: CodeRabbitReportFormData) => void\n}\n\n/**\n * Get default date range (last 7 days)\n */\nfunction getDefaultDateRange() {\n  const today = new Date()\n  const weekAgo = new Date(today.getTime() - 7 * 24 * 60 * 60 * 1000)\n  return {\n    fromDate: weekAgo.toISOString().split('T')[0],\n    toDate: today.toISOString().split('T')[0],\n  }\n}\n\n/**\n * Get initial form data with sensible defaults\n */\nexport function getInitialFormData(): CodeRabbitReportFormData {\n  const { fromDate, toDate } = getDefaultDateRange()\n  return {\n    fromDate,\n    toDate,\n    promptTemplate: '',\n    customPrompt: '',\n    groupBy: 'NONE',\n    subgroupBy: 'NONE',\n    orgId: '',\n    filters: [],\n  }\n}\n\nexport function CodeRabbitReportForm({\n  value,\n  onChange,\n}: CodeRabbitReportFormProps) {\n  const [showAdvanced, setShowAdvanced] = useState(false)\n  const initializedRef = useRef(false)\n\n  // Set default dates on mount if not provided\n  useEffect(() => {\n    if (initializedRef.current) return\n    initializedRef.current = true\n\n    if (!value.fromDate || !value.toDate) {\n      const { fromDate, toDate } = getDefaultDateRange()\n      onChange({\n        ...value,\n        fromDate: value.fromDate || fromDate,\n        toDate: value.toDate || toDate,\n      })\n    }\n  }, [value, onChange])\n\n  const addFilter = () => {\n    onChange({\n      ...value,\n      filters: [\n        ...value.filters,\n        { parameter: 'REPOSITORY', operator: 'IN', values: '' },\n      ],\n    })\n  }\n\n  const removeFilter = (index: number) => {\n    onChange({\n      ...value,\n      filters: value.filters.filter((_, i) => i !== index),\n    })\n  }\n\n  const updateFilter = (\n    index: number,\n    field: keyof FilterParameterForm,\n    newValue: string,\n  ) => {\n    const newFilters = [...value.filters]\n    newFilters[index] = { ...newFilters[index], [field]: newValue }\n    onChange({ ...value, filters: newFilters })\n  }\n\n  return (\n    <div className=\"space-y-4\">\n      {/* Date Range */}\n      <div className=\"grid grid-cols-2 gap-4\">\n        <div className=\"space-y-2\">\n          <Label htmlFor=\"fromDate\" className=\"text-sm font-semibold\">\n            From Date\n          </Label>\n          <Input\n            id=\"fromDate\"\n            type=\"date\"\n            value={value.fromDate}\n            onChange={(e) => onChange({ ...value, fromDate: e.target.value })}\n            className=\"h-11\"\n          />\n        </div>\n        <div className=\"space-y-2\">\n          <Label htmlFor=\"toDate\" className=\"text-sm font-semibold\">\n            To Date\n          </Label>\n          <Input\n            id=\"toDate\"\n            type=\"date\"\n            value={value.toDate}\n            onChange={(e) => onChange({ ...value, toDate: e.target.value })}\n            className=\"h-11\"\n          />\n        </div>\n      </div>\n\n      {/* Template Selection */}\n      <div className=\"space-y-2.5\">\n        <Label htmlFor=\"template\" className=\"text-sm font-semibold\">\n          Report Template\n        </Label>\n        <Select\n          value={value.promptTemplate}\n          onValueChange={(promptTemplate) =>\n            onChange({ ...value, promptTemplate })\n          }\n        >\n          <SelectTrigger id=\"template\" className=\"h-11\">\n            <SelectValue placeholder=\"Select template\" />\n          </SelectTrigger>\n          <SelectContent>\n            {PROMPT_TEMPLATES.map((template) => (\n              <SelectItem\n                key={template}\n                value={template}\n                disabled={template === 'Select template'}\n              >\n                {template}\n              </SelectItem>\n            ))}\n          </SelectContent>\n        </Select>\n      </div>\n\n      {/* Custom Prompt (shown only for Custom template) */}\n      {value.promptTemplate === 'Custom' && (\n        <div className=\"space-y-2\">\n          <Label htmlFor=\"prompt\">Custom Prompt</Label>\n          <Textarea\n            id=\"prompt\"\n            value={value.customPrompt}\n            onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) =>\n              onChange({ ...value, customPrompt: e.target.value })\n            }\n            placeholder=\"Describe what you want in the report...\"\n            rows={4}\n            required\n          />\n        </div>\n      )}\n\n      {/* Advanced Options Toggle */}\n      <Button\n        type=\"button\"\n        variant=\"outline\"\n        size=\"sm\"\n        onClick={() => setShowAdvanced(!showAdvanced)}\n        className=\"w-full\"\n      >\n        {showAdvanced ? 'Hide' : 'Show'} Advanced Options\n      </Button>\n\n      {showAdvanced && (\n        <div className=\"space-y-4 pt-5 border-t bg-muted/20 -mx-6 px-6 pb-1\">\n          {/* Group By */}\n          <div className=\"space-y-2\">\n            <Label htmlFor=\"groupBy\">Group By</Label>\n            <Select\n              value={value.groupBy}\n              onValueChange={(groupBy) => onChange({ ...value, groupBy })}\n            >\n              <SelectTrigger id=\"groupBy\">\n                <SelectValue />\n              </SelectTrigger>\n              <SelectContent>\n                {GROUP_BY_OPTIONS.map((option) => (\n                  <SelectItem key={option.value} value={option.value}>\n                    {option.label}\n                  </SelectItem>\n                ))}\n              </SelectContent>\n            </Select>\n          </div>\n\n          {/* Subgroup By */}\n          <div className=\"space-y-2\">\n            <Label htmlFor=\"subgroupBy\">Subgroup By (Optional)</Label>\n            <Select\n              value={value.subgroupBy}\n              onValueChange={(subgroupBy) => onChange({ ...value, subgroupBy })}\n            >\n              <SelectTrigger id=\"subgroupBy\">\n                <SelectValue placeholder=\"None\" />\n              </SelectTrigger>\n              <SelectContent>\n                {GROUP_BY_OPTIONS.map((option) => (\n                  <SelectItem key={option.value} value={option.value}>\n                    {option.label}\n                  </SelectItem>\n                ))}\n              </SelectContent>\n            </Select>\n          </div>\n\n          {/* Organization ID */}\n          <div className=\"space-y-2\">\n            <Label htmlFor=\"orgId\">Organization ID (Optional)</Label>\n            <Input\n              id=\"orgId\"\n              value={value.orgId}\n              onChange={(e) => onChange({ ...value, orgId: e.target.value })}\n              placeholder=\"Enter organization ID\"\n            />\n          </div>\n\n          {/* Filters */}\n          <div className=\"space-y-3\">\n            <div className=\"flex items-center justify-between\">\n              <Label className=\"text-sm font-medium\">Filters (Optional)</Label>\n              <Button\n                type=\"button\"\n                variant=\"outline\"\n                size=\"sm\"\n                onClick={addFilter}\n                className=\"h-8\"\n              >\n                <Plus className=\"h-3.5 w-3.5 mr-1.5\" />\n                Add Filter\n              </Button>\n            </div>\n\n            {value.filters.map((filter, index) => (\n              <div\n                key={index}\n                className=\"grid grid-cols-[1fr,1fr,2fr,auto] gap-3 items-end p-4 border rounded-lg bg-muted/30 hover:bg-muted/50 transition-colors\"\n              >\n                <div className=\"space-y-1.5\">\n                  <Label className=\"text-xs\">Parameter</Label>\n                  <Select\n                    value={filter.parameter}\n                    onValueChange={(val) =>\n                      updateFilter(index, 'parameter', val)\n                    }\n                  >\n                    <SelectTrigger>\n                      <SelectValue />\n                    </SelectTrigger>\n                    <SelectContent>\n                      {FILTER_PARAMETERS.map((param) => (\n                        <SelectItem key={param.value} value={param.value}>\n                          {param.label}\n                        </SelectItem>\n                      ))}\n                    </SelectContent>\n                  </Select>\n                </div>\n\n                <div className=\"space-y-1.5\">\n                  <Label className=\"text-xs\">Operator</Label>\n                  <Select\n                    value={filter.operator}\n                    onValueChange={(val) =>\n                      updateFilter(index, 'operator', val)\n                    }\n                  >\n                    <SelectTrigger>\n                      <SelectValue />\n                    </SelectTrigger>\n                    <SelectContent>\n                      {FILTER_OPERATORS.map((op) => (\n                        <SelectItem key={op.value} value={op.value}>\n                          {op.label}\n                        </SelectItem>\n                      ))}\n                    </SelectContent>\n                  </Select>\n                </div>\n\n                <div className=\"space-y-1.5\">\n                  <Label className=\"text-xs\">Values (pipe-separated)</Label>\n                  <Input\n                    value={filter.values}\n                    onChange={(e) =>\n                      updateFilter(index, 'values', e.target.value)\n                    }\n                    placeholder=\"value1 | value2\"\n                  />\n                </div>\n\n                <Button\n                  type=\"button\"\n                  variant=\"ghost\"\n                  size=\"icon\"\n                  onClick={() => removeFilter(index)}\n                  className=\"text-destructive hover:text-destructive\"\n                >\n                  <X className=\"h-4 w-4\" />\n                </Button>\n              </div>\n            ))}\n\n            {value.filters.length === 0 && (\n              <div className=\"text-center py-6 px-4 border border-dashed rounded-lg bg-muted/20\">\n                <p className=\"text-sm text-muted-foreground\">\n                  No filters added. Click &quot;Add Filter&quot; to narrow down the report\n                  scope. Use pipe (|) to separate multiple values.\n                </p>\n              </div>\n            )}\n          </div>\n        </div>\n      )}\n    </div>\n  )\n}\n\nexport function getCodeRabbitReportPayload(data: CodeRabbitReportFormData) {\n  const isCustomPrompt = data.promptTemplate === 'Custom'\n\n  // Convert pipe-separated filter values to arrays\n  const parameters =\n    data.filters.length > 0\n      ? data.filters\n          .filter((f) => f.values.trim())\n          .map((f) => ({\n            parameter: f.parameter as FilterParameter,\n            operator: f.operator as FilterOperator,\n            values: f.values.split('|').map((v) => v.trim()),\n          }))\n      : undefined\n\n  return {\n    from: data.fromDate,\n    to: data.toDate,\n    promptTemplate: isCustomPrompt\n      ? undefined\n      : (data.promptTemplate as PromptTemplate),\n    prompt: isCustomPrompt ? data.customPrompt : undefined,\n    groupBy: data.groupBy as GroupBy,\n    subgroupBy:\n      data.subgroupBy && data.subgroupBy !== 'NONE'\n        ? (data.subgroupBy as GroupBy)\n        : undefined,\n    orgId: data.orgId || undefined,\n    parameters,\n  }\n}\n",
      "type": "registry:component"
    }
  ],
  "categories": [
    "forms",
    "components"
  ],
  "type": "registry:component"
}