Skip to main content
Glama

HANA Cloud MCP Server

by HatriGt
EnvironmentManager.jsx7.29 kB
import { useState, useEffect } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { GradientButton } from './ui'; import { cn } from '../utils/cn'; const EnvironmentManager = ({ isOpen, onClose, onSave }) => { const [environments, setEnvironments] = useState([ { id: 'development', name: 'Development', color: 'blue', required: false }, { id: 'staging', name: 'Staging', color: 'amber', required: false }, { id: 'production', name: 'Production', color: 'green', required: false } ]); const [newEnvironmentName, setNewEnvironmentName] = useState(''); const [selectedColor, setSelectedColor] = useState('purple'); useEffect(() => { if (!isOpen) return; const onKeyDown = (e) => { if (e.key === 'Escape') onClose(); }; window.addEventListener('keydown', onKeyDown); return () => window.removeEventListener('keydown', onKeyDown); }, [isOpen, onClose]); const colorOptions = [ { id: 'blue', name: 'Blue', class: 'bg-blue-500' }, { id: 'green', name: 'Green', class: 'bg-green-500' }, { id: 'amber', name: 'Amber', class: 'bg-amber-500' }, { id: 'purple', name: 'Purple', class: 'bg-purple-500' }, { id: 'indigo', name: 'Indigo', class: 'bg-indigo-500' }, { id: 'red', name: 'Red', class: 'bg-red-500' }, { id: 'pink', name: 'Pink', class: 'bg-pink-500' }, { id: 'teal', name: 'Teal', class: 'bg-teal-500' } ]; useEffect(() => { // Load existing environments from localStorage or API const savedEnvironments = localStorage.getItem('hana-environments'); if (savedEnvironments) { setEnvironments(JSON.parse(savedEnvironments)); } }, []); const addEnvironment = () => { if (!newEnvironmentName.trim()) return; const newEnv = { id: newEnvironmentName.toLowerCase().replace(/\s+/g, '-'), name: newEnvironmentName, color: selectedColor, required: false }; const updatedEnvironments = [...environments, newEnv]; setEnvironments(updatedEnvironments); setNewEnvironmentName(''); setSelectedColor('purple'); }; const removeEnvironment = (envId) => { setEnvironments(environments.filter(env => env.id !== envId)); }; const handleSave = () => { // Save to localStorage (in real app, this would be an API call) localStorage.setItem('hana-environments', JSON.stringify(environments)); onSave(environments); onClose(); }; if (!isOpen) return null; return ( <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"> <motion.div initial={{ opacity: 0, scale: 0.95 }} animate={{ opacity: 1, scale: 1 }} exit={{ opacity: 0, scale: 0.95 }} className="bg-white rounded-xl shadow-2xl p-6 w-full max-w-2xl max-h-[80vh] overflow-y-auto" > <div className="flex items-center justify-between mb-6"> <h2 className="text-xl font-semibold text-gray-900">Manage Environments</h2> <button onClick={onClose} className="text-gray-400 hover:text-gray-600" > <svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" /> </svg> </button> </div> {/* Current Environments */} <div className="mb-6"> <h3 className="text-lg font-medium text-gray-900 mb-3">Current Environments</h3> <div className="space-y-2"> {environments.map((env) => ( <div key={env.id} className="flex items-center justify-between p-3 bg-gray-50 rounded-lg" > <div className="flex items-center space-x-3"> <div className={cn('w-4 h-4 rounded-full', `bg-${env.color}-500`)} /> <span className="font-medium text-gray-900">{env.name}</span> <span className="text-sm text-gray-500">({env.id})</span> </div> <button onClick={() => removeEnvironment(env.id)} className="text-red-600 hover:text-red-800 text-sm" > Remove </button> </div> ))} </div> </div> {/* Add New Environment */} <div className="mb-6"> <h3 className="text-lg font-medium text-gray-900 mb-3">Add New Environment</h3> <div className="space-y-4"> <div> <label className="block text-sm font-medium text-gray-700 mb-1"> Environment Name </label> <input type="text" value={newEnvironmentName} onChange={(e) => setNewEnvironmentName(e.target.value)} placeholder="e.g., Pre-Production, QA, Testing" className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" /> </div> <div> <label className="block text-sm font-medium text-gray-700 mb-2"> Color </label> <div className="flex flex-wrap gap-2"> {colorOptions.map((color) => ( <button key={color.id} onClick={() => setSelectedColor(color.id)} className={cn( 'w-8 h-8 rounded-full border-2 transition-all', color.class, selectedColor === color.id ? 'border-gray-800 scale-110' : 'border-gray-300 hover:scale-105' )} title={color.name} /> ))} </div> </div> <GradientButton onClick={addEnvironment} disabled={!newEnvironmentName.trim()} className="w-full" > Add Environment </GradientButton> </div> </div> {/* Note */} <div className="bg-blue-50 border border-blue-200 rounded-lg p-4 mb-6"> <div className="flex"> <svg className="w-5 h-5 text-blue-600 mr-2 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /> </svg> <div> <p className="text-sm text-blue-800"> <strong>Note:</strong> Environments are optional for databases. You can configure any combination of environments for each database based on your needs. </p> </div> </div> </div> {/* Actions */} <div className="flex justify-end space-x-3"> <GradientButton variant="secondary" onClick={onClose}> Cancel </GradientButton> <GradientButton onClick={handleSave}> Save Changes </GradientButton> </div> </motion.div> </div> ); }; export default EnvironmentManager;

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/HatriGt/hana-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server