File size: 3,751 Bytes
f0743f4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import React, { useEffect } from 'react';
import { useForm, Controller } from 'react-hook-form';
import { Button, Input, Label, OGDialog, OGDialogTemplate } from '@librechat/client';
import type { ConfigFieldDetail } from '~/common';
import { useLocalize } from '~/hooks';

interface MCPConfigDialogProps {
  isOpen: boolean;
  onOpenChange: (isOpen: boolean) => void;
  fieldsSchema: Record<string, ConfigFieldDetail>;
  initialValues: Record<string, string>;
  onSave: (updatedValues: Record<string, string>) => void;
  isSubmitting?: boolean;
  onRevoke?: () => void;
  serverName: string;
}

export default function MCPConfigDialog({
  isOpen,
  onOpenChange,
  fieldsSchema,
  initialValues,
  onSave,
  isSubmitting = false,
  onRevoke,
  serverName,
}: MCPConfigDialogProps) {
  const localize = useLocalize();
  const {
    control,
    handleSubmit,
    reset,
    formState: { errors },
  } = useForm<Record<string, string>>({
    defaultValues: initialValues,
  });

  useEffect(() => {
    if (isOpen) {
      reset(initialValues);
    }
  }, [isOpen, initialValues, reset]);

  const onFormSubmit = (data: Record<string, string>) => {
    onSave(data);
  };

  const handleRevoke = () => {
    if (onRevoke) {
      onRevoke();
    }
  };

  const dialogTitle = localize('com_ui_configure_mcp_variables_for', { 0: serverName });

  return (
    <OGDialog open={isOpen} onOpenChange={onOpenChange}>
      <OGDialogTemplate
        className="sm:max-w-lg"
        title={dialogTitle}
        headerClassName="px-6 pt-6 pb-4"
        main={
          <form onSubmit={handleSubmit(onFormSubmit)} className="space-y-4 px-6 pb-2">
            {Object.entries(fieldsSchema).map(([key, details]) => (
              <div key={key} className="space-y-2">
                <Label htmlFor={key} className="text-sm font-medium">
                  {details.title}
                </Label>
                <Controller
                  name={key}
                  control={control}
                  defaultValue={initialValues[key] || ''}
                  render={({ field }) => (
                    <Input
                      id={key}
                      type="text"
                      {...field}
                      placeholder={localize('com_ui_mcp_enter_var', { 0: details.title })}
                      className="w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white sm:text-sm"
                    />
                  )}
                />
                {details.description && (
                  <p
                    className="text-xs text-text-secondary [&_a]:text-blue-500 [&_a]:hover:text-blue-600 dark:[&_a]:text-blue-400 dark:[&_a]:hover:text-blue-300"
                    dangerouslySetInnerHTML={{ __html: details.description }}
                  />
                )}
                {errors[key] && <p className="text-xs text-red-500">{errors[key]?.message}</p>}
              </div>
            ))}
          </form>
        }
        selection={{
          selectHandler: handleSubmit(onFormSubmit),
          selectClasses: 'bg-green-500 hover:bg-green-600 text-white',
          selectText: isSubmitting ? localize('com_ui_saving') : localize('com_ui_save'),
        }}
        buttons={
          onRevoke && (
            <Button
              onClick={handleRevoke}
              className="bg-red-600 text-white hover:bg-red-700 dark:hover:bg-red-800"
              disabled={isSubmitting}
            >
              {localize('com_ui_revoke')}
            </Button>
          )
        }
        footerClassName="flex justify-end gap-2 px-6 pb-6 pt-2"
        showCancelButton={true}
      />
    </OGDialog>
  );
}