diff --git a/package-lock.json b/package-lock.json index 906a82a..951d6ec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,6 +25,7 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "date-fns": "^4.1.0", + "image-resize-compress": "^2.1.1", "lucide-react": "^0.484.0", "marked": "^15.0.8", "menubar": "^9.5.1", @@ -7737,6 +7738,15 @@ ], "license": "BSD-3-Clause" }, + "node_modules/image-resize-compress": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/image-resize-compress/-/image-resize-compress-2.1.1.tgz", + "integrity": "sha512-aF4O1ZzAM0wDziIQZdqlxvDBe163J1Kiu+hSXbYNaGDcD4ggqAgRLLtRmpspnpJPHa4PkhVjwOshzBMHbOWESQ==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/import-fresh": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", diff --git a/package.json b/package.json index 14edab5..310ba23 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "date-fns": "^4.1.0", + "image-resize-compress": "^2.1.1", "lucide-react": "^0.484.0", "marked": "^15.0.8", "menubar": "^9.5.1", @@ -48,4 +49,4 @@ "xlsx": "^0.18.5" }, "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" -} \ No newline at end of file +} diff --git a/public/assets/js/index.min.js b/public/assets/js/index.min.js new file mode 100644 index 0000000..aa0a8f9 --- /dev/null +++ b/public/assets/js/index.min.js @@ -0,0 +1,12 @@ +/** + * Skipped minification because the original files appears to be already minified. + * Original file: /npm/image-resize-compress@2.1.1/dist/index.js + * + * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files + */ +var h=e=>({png:"image/png",webp:"image/webp",bmp:"image/bmp",gif:"image/gif",jpeg:"image/jpeg"})[e]||"image/jpeg",w=(e,t="auto",r="auto")=>{let o=t==="auto"||t===0,m=r==="auto"||r===0;if(!o&&!m)return{width:t,height:r};if(!o){let n=e.naturalWidth/t;return{width:t,height:Math.round((e.naturalHeight/n+Number.EPSILON)*100)/100}}if(!m){let n=e.naturalHeight/r;return{width:Math.round((e.naturalWidth/n+Number.EPSILON)*100)/100,height:r}}return{width:e.naturalWidth,height:e.naturalHeight}},E=async(e,t=100,r="auto",o="auto",m=null,n=null)=>{if(!(e instanceof Blob))throw new TypeError(`Expected a Blob or File, but got ${typeof e}.`);if(e.size===0)throw new Error("Failed to load the image. The file might be corrupt or empty.");if(t<=0)throw new RangeError("Quality must be greater than 0.");if(typeof r=="number"&&r<0||typeof o=="number"&&o<0)throw new RangeError("Invalid width or height value!");let a=m?h(m):e.type,g=t<1?t:t/100;return new Promise((p,l)=>{let u=new FileReader;u.onload=()=>{let s=new Image;s.src=u.result,s.onload=()=>{let i=document.createElement("canvas"),d=w(s,r,o);i.width=d.width,i.height=d.height;let f=i.getContext("2d");if(!f){l(new Error("Failed to get canvas context."));return}n&&a==="image/png"&&(f.fillStyle=n,f.fillRect(0,0,i.width,i.height)),f.drawImage(s,0,0,i.width,i.height),i.toBlob(b=>{if(b===null)return l(new Error("Failed to generate image blob."));p(new Blob([b],{type:a}))},a,g)},s.onerror=()=>{l(new Error("Failed to load the image. The file might be corrupt or empty."))}},u.onerror=()=>l(new Error("Failed to read the blob as a Data URL.")),u.readAsDataURL(e)})},c=E;var F=async(e,t=100,r="auto",o="auto",m,n)=>{try{let a=await fetch(e,n);if(!a.ok)throw new Error(`Failed to fetch image: ${a.statusText}`);let g=await a.blob();return await c(g,t,r,o,m)}catch(a){throw new Error(`Failed to process the image from URL. Check CORS or network issues. Error: ${a}`)}},y=F;var I=e=>new Promise((t,r)=>{if(e.size===0)return r(new Error("Cannot convert empty Blob."));if(e.size>10485760)return r(new Error("File size exceeds the maximum allowed limit."));let o=new FileReader;o.onloadend=()=>{o.result?t(o.result):r(new Error("Failed to convert blob to DataURL."))},o.onerror=()=>r(new Error("Error reading blob.")),o.readAsDataURL(e)}),R=I;var L=async(e,t)=>{try{let r=await fetch(e,t);if(!r.ok)throw new Error(`Failed to fetch image: ${r.statusText}`);return await r.blob()}catch(r){throw new Error(`Failed to fetch image from URL. Error: ${r}`)}},T=L;export{R as blobToURL,c as fromBlob,y as fromURL,T as urlToBlob}; +/*! + * image-resize-compress + * Copyright(c) 2024 Álef Duarte + * MIT Licensed + */ \ No newline at end of file diff --git a/src/components/BuyServices/NewKubernetisUtho.jsx b/src/components/BuyServices/NewKubernetisUtho.jsx new file mode 100644 index 0000000..e9a5bd9 --- /dev/null +++ b/src/components/BuyServices/NewKubernetisUtho.jsx @@ -0,0 +1,433 @@ +import React, { useState, useEffect } from "react"; +import { Button } from '../ui/button'; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../ui/card"; +import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from "../ui/select"; +import { Input } from "../ui/input"; +import { Label } from "../ui/label"; +import Loader from "../ui/loader"; +import { useToast } from "../ui/toast"; +import { Switch } from "../ui/switch"; + +export default function NewKubernetesService() { + const { showToast } = useToast(); + const [isLoading, setIsLoading] = useState(false); + const [isFetchingData, setIsFetchingData] = useState(true); + const [plans, setPlans] = useState([]); + const [vpcs, setVpcs] = useState([]); + const UTHO_API_KEY = "Bearer IoNXhkRJsQPyOEqFMceSfzuKaDLrpxUCATgZjiVdvYlBHbwWmGtn"; + + const [formData, setFormData] = useState({ + datacenter: "mumbai", + plan: "", + name: "", + k8s_version: "1.27", + nodes: 1, + storage: "50", + public_ip: true, + auto_scaling: false, + min_nodes: 1, + max_nodes: 3, + vpc: "", + subnet: "" + }); + + useEffect(() => { + const fetchInitialData = async () => { + setIsFetchingData(true); + try { + const [plansResponse, vpcsResponse] = await Promise.all([ + fetch("https://api.utho.com/v2/plans", { + headers: { + "Authorization": UTHO_API_KEY, + "Content-Type": "application/json" + } + }), + fetch("https://api.utho.com/v2/vpc", { + headers: { + "Authorization": UTHO_API_KEY, + "Content-Type": "application/json" + } + }) + ]); + + const plansData = await plansResponse.json(); + const vpcsData = await vpcsResponse.json(); +console.log('vpcsData.vpc', vpcsData.vpc) + setPlans(plansData.plans || []); + setVpcs(vpcsData.vpc || []); + + // Set default VPC and subnet if available + if (vpcsData.vpc?.length > 0) { + const firstVpc = vpcsData.vpc[0]; + const firstSubnet = firstVpc.subnets?.[0]?.id || ""; + setFormData(prev => ({ + ...prev, + vpc: firstVpc.id, + subnet: firstSubnet + })); + } + } catch (error) { + console.error("Initial data fetch error:", error); + showToast({ + title: "Error", + description: "Failed to load initial configuration data", + variant: "destructive" + }); + } finally { + setIsFetchingData(false); + } + }; + + fetchInitialData(); + }, []); + + const handleVpcChange = (vpcId) => { + const selectedVpc = vpcs.find(vpc => vpc.id === vpcId); + const firstSubnet = selectedVpc?.subnet?.[0]?.id || ""; + setFormData(prev => ({ + ...prev, + vpc: vpcId, + subnet: firstSubnet + })); + }; + + const getCurrentSubnets = () => { + const selectedVpc = vpcs.find(vpc => vpc.id === formData.vpc); + return selectedVpc?.subnets || []; + }; + + const handleSubmit = async (e) => { + e.preventDefault(); + setIsLoading(true); + + try { + if (!formData.vpc || !formData.subnet) { + throw new Error("Please select both VPC and Subnet to proceed"); + } + + const payload = { + datacenter: formData.datacenter, + plan: formData.plan, + name: formData.name, + k8s_version: formData.k8s_version, + nodes: formData.nodes, + storage: formData.storage, + public_ip: formData.public_ip, + vpc: formData.vpc, + subnet: formData.subnet + }; + + if (formData.auto_scaling) { + payload.auto_scaling = true; + payload.min_nodes = formData.min_nodes; + payload.max_nodes = formData.max_nodes; + } + + const response = await fetch("https://api.utho.com/v2/kubernetes/deploy", { + method: "POST", + headers: { + "Authorization": UTHO_API_KEY, + "Content-Type": "application/json" + }, + body: JSON.stringify(payload) + }); + + const data = await response.json(); + + if (!response.ok) { + throw new Error(data.message || "Failed to deploy Kubernetes cluster"); + } + + if (data.status === "success") { + showToast({ + title: "Success", + description: `Cluster ${data.cluster_id || data.id} is being deployed`, + variant: "success" + }); + setFormData(prev => ({ + ...prev, + name: "", + plan: "", + nodes: 1 + })); + } else { + throw new Error(data.message || "Failed to deploy Kubernetes cluster"); + } + } catch (error) { + showToast({ + title: "Deployment Failed", + description: error.message, + variant: "destructive" + }); + console.error("Deployment error:", error); + } finally { + setIsLoading(false); + } + }; + + const handleChange = (e) => { + const { name, value, type, checked } = e.target; + setFormData(prev => ({ + ...prev, + [name]: type === "checkbox" ? checked : value + })); + }; + + if (isFetchingData) { + return ( +
You selected {selectedCycle} plan at ₹{selectedPrice}
- )} -You selected {selectedCycle} plan at ₹{selectedPrice}
+ // )} + //