Type fixes & Docker

This commit is contained in:
headlessdev
2025-04-13 21:10:17 +02:00
parent dcce66a449
commit eadaf75b74
76 changed files with 21644 additions and 264 deletions

View File

@@ -1,4 +1,4 @@
import { AppSidebar } from "@/components/app-sidebar"
import { AppSidebar } from "@/components/app-sidebar";
import {
Breadcrumb,
BreadcrumbItem,
@@ -6,40 +6,38 @@ import {
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from "@/components/ui/breadcrumb"
import { Separator } from "@/components/ui/separator"
} from "@/components/ui/breadcrumb";
import { Separator } from "@/components/ui/separator";
import {
SidebarInset,
SidebarProvider,
SidebarTrigger,
} from "@/components/ui/sidebar"
import { useEffect, useState } from "react"
import axios from "axios"
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card"
import { Skeleton } from "@/components/ui/skeleton"
} from "@/components/ui/sidebar";
import { useEffect, useState } from "react";
import axios from "axios"; // Korrekter Import
import { Card, CardHeader } from "@/components/ui/card";
interface StatsResponse {
serverCount: number;
applicationCount: number;
onlineApplicationsCount: number;
}
export default function Dashboard() {
const [serverCount, setServerCount] = useState(0)
const [applicationCount, setApplicationCount] = useState(0)
const [onlineApplicationsCount, setOnlineApplicationsCount] = useState(0)
const [serverCount, setServerCount] = useState<number>(0);
const [applicationCount, setApplicationCount] = useState<number>(0);
const [onlineApplicationsCount, setOnlineApplicationsCount] = useState<number>(0);
const getStats = async () => {
try {
const response = await axios.post('/api/dashboard/get', { });
setServerCount(response.data.serverCount)
setApplicationCount(response.data.applicationCount)
setOnlineApplicationsCount(response.data.onlineApplicationsCount)
const response = await axios.post<StatsResponse>('/api/dashboard/get', {});
setServerCount(response.data.serverCount);
setApplicationCount(response.data.applicationCount);
setOnlineApplicationsCount(response.data.onlineApplicationsCount);
} catch (error: any) {
console.log(error.response);
console.log("Axios error:", error.response?.data);
}
}
};
useEffect(() => {
getStats();
@@ -94,7 +92,9 @@ export default function Dashboard() {
<CardHeader>
<div className="flex items-center justify-center w-full">
<div className="flex flex-col items-center justify-center">
<span className="text-2xl font-bold">{onlineApplicationsCount}/{applicationCount}</span>
<span className="text-2xl font-bold">
{onlineApplicationsCount}/{applicationCount}
</span>
<span className="text-md">Applications are online</span>
</div>
</div>
@@ -102,15 +102,15 @@ export default function Dashboard() {
</Card>
</div>
<div className="h-72 w-full rounded-xl flex items-center justify-center bg-muted">
<span className="text-gray-400 text-2xl">COMMING SOON</span>
<span className="text-gray-400 text-2xl">COMING SOON</span>
</div>
<div className="pt-4">
<div className="h-72 w-full rounded-xl flex items-center justify-center bg-muted">
<span className="text-gray-400 text-2xl">COMMING SOON</span>
<span className="text-gray-400 text-2xl">COMING SOON</span>
</div>
</div>
</div>
</SidebarInset>
</SidebarProvider>
)
);
}

View File

@@ -57,28 +57,51 @@ import {
} from "@/components/ui/select";
import Cookies from "js-cookie";
import { useState, useEffect } from "react";
import axios from 'axios';
import axios from "axios";
interface Application {
id: number;
name: string;
description?: string;
icon?: string;
publicURL: string;
localURL?: string;
server?: string;
online: boolean;
serverId: number;
}
interface Server {
id: number;
name: string;
}
interface ApplicationsResponse {
applications: Application[];
servers: Server[];
maxPage: number;
}
export default function Dashboard() {
const [name, setName] = useState("");
const [description, setDescription] = useState("");
const [icon, setIcon] = useState("");
const [publicURL, setPublicURL] = useState("");
const [localURL, setLocalURL] = useState("");
const [name, setName] = useState<string>("");
const [description, setDescription] = useState<string>("");
const [icon, setIcon] = useState<string>("");
const [publicURL, setPublicURL] = useState<string>("");
const [localURL, setLocalURL] = useState<string>("");
const [serverId, setServerId] = useState<number | null>(null);
const [currentPage, setCurrentPage] = useState(1);
const [maxPage, setMaxPage] = useState(1);
const [itemsPerPage, setItemsPerPage] = useState(5);
const [applications, setApplications] = useState([]);
const [servers, setServers] = useState([]);
const [isGridLayout, setIsGridLayout] = useState(false);
const [loading, setLoading] = useState(true);
const [currentPage, setCurrentPage] = useState<number>(1);
const [maxPage, setMaxPage] = useState<number>(1);
const [itemsPerPage, setItemsPerPage] = useState<number>(5);
const [applications, setApplications] = useState<Application[]>([]);
const [servers, setServers] = useState<Server[]>([]);
const [isGridLayout, setIsGridLayout] = useState<boolean>(false);
const [loading, setLoading] = useState<boolean>(true);
useEffect(() => {
const savedLayout = Cookies.get('layoutPreference-app');
const layout_bool = savedLayout === 'grid'
const layout_bool = savedLayout === 'grid';
setIsGridLayout(layout_bool);
setItemsPerPage(layout_bool ? 15 : 5)
setItemsPerPage(layout_bool ? 15 : 5);
}, []);
const toggleLayout = () => {
@@ -104,20 +127,23 @@ export default function Dashboard() {
});
getApplications();
} catch (error: any) {
console.log(error.response.data);
console.log(error.response?.data);
}
}
const getApplications = async () => {
try {
setLoading(true)
const response = await axios.post('/api/applications/get', { page: currentPage, ITEMS_PER_PAGE: itemsPerPage });
setLoading(true);
const response = await axios.post<ApplicationsResponse>(
'/api/applications/get',
{ page: currentPage, ITEMS_PER_PAGE: itemsPerPage }
);
setApplications(response.data.applications);
setServers(response.data.servers);
setMaxPage(response.data.maxPage);
setLoading(false)
setLoading(false);
} catch (error: any) {
console.log(error.response);
console.log(error.response?.data);
}
}
@@ -133,7 +159,7 @@ export default function Dashboard() {
await axios.post('/api/applications/delete', { id });
getApplications();
} catch (error: any) {
console.log(error.response.data);
console.log(error.response?.data);
}
}
@@ -315,7 +341,7 @@ export default function Dashboard() {
<div className='inline-block' role='status' aria-label='loading'>
<svg className='w-6 h-6 stroke-white animate-spin ' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'>
<g clip-path='url(#clip0_9023_61563)'>
<path d='M14.6437 2.05426C11.9803 1.2966 9.01686 1.64245 6.50315 3.25548C1.85499 6.23817 0.504864 12.4242 3.48756 17.0724C6.47025 21.7205 12.6563 23.0706 17.3044 20.088C20.4971 18.0393 22.1338 14.4793 21.8792 10.9444' stroke='stroke-current' stroke-width='1.4' stroke-linecap='round' class='my-path'></path>
<path d='M14.6437 2.05426C11.9803 1.2966 9.01686 1.64245 6.50315 3.25548C1.85499 6.23817 0.504864 12.4242 3.48756 17.0724C6.47025 21.7205 12.6563 23.0706 17.3044 20.088C20.4971 18.0393 22.1338 14.4793 21.8792 10.9444' stroke='stroke-current' stroke-width='1.4' stroke-linecap='round' className='my-path'></path>
</g>
<defs>
<clipPath id='clip0_9023_61563'>

View File

@@ -41,7 +41,7 @@ export default function DashboardPage() {
<div className='inline-block' role='status' aria-label='loading'>
<svg className='w-6 h-6 stroke-white animate-spin ' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'>
<g clip-path='url(#clip0_9023_61563)'>
<path d='M14.6437 2.05426C11.9803 1.2966 9.01686 1.64245 6.50315 3.25548C1.85499 6.23817 0.504864 12.4242 3.48756 17.0724C6.47025 21.7205 12.6563 23.0706 17.3044 20.088C20.4971 18.0393 22.1338 14.4793 21.8792 10.9444' stroke='stroke-current' stroke-width='1.4' stroke-linecap='round' class='my-path'></path>
<path d='M14.6437 2.05426C11.9803 1.2966 9.01686 1.64245 6.50315 3.25548C1.85499 6.23817 0.504864 12.4242 3.48756 17.0724C6.47025 21.7205 12.6563 23.0706 17.3044 20.088C20.4971 18.0393 22.1338 14.4793 21.8792 10.9444' stroke='stroke-current' stroke-width='1.4' stroke-linecap='round' className='my-path'></path>
</g>
<defs>
<clipPath id='clip0_9023_61563'>

View File

@@ -13,7 +13,7 @@ import {
SidebarProvider,
SidebarTrigger,
} from "@/components/ui/sidebar";
import { ReactFlow, Controls, Background } from "@xyflow/react";
import { ReactFlow, Controls, Background, ConnectionLineType } from "@xyflow/react";
import "@xyflow/react/dist/style.css";
import { useEffect, useState } from "react";
@@ -78,12 +78,12 @@ export default function Dashboard() {
className="dark:bg-black rounded-lg"
>
<ReactFlow
nodes={nodes}
edges={edges}
fitView
fitViewOptions={{ padding: 0.2 }}
connectionLineType="straight"
className="dark:[&_.react-flow__edge-path]:stroke-slate-500"
nodes={nodes}
edges={edges}
fitView
fitViewOptions={{ padding: 0.2 }}
connectionLineType={ConnectionLineType.Straight}
className="dark:[&_.react-flow__edge-path]:stroke-slate-500"
>
<Background
color="#64748b"

View File

@@ -41,7 +41,7 @@ export default function DashboardPage() {
<div className='inline-block' role='status' aria-label='loading'>
<svg className='w-6 h-6 stroke-white animate-spin ' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'>
<g clip-path='url(#clip0_9023_61563)'>
<path d='M14.6437 2.05426C11.9803 1.2966 9.01686 1.64245 6.50315 3.25548C1.85499 6.23817 0.504864 12.4242 3.48756 17.0724C6.47025 21.7205 12.6563 23.0706 17.3044 20.088C20.4971 18.0393 22.1338 14.4793 21.8792 10.9444' stroke='stroke-current' stroke-width='1.4' stroke-linecap='round' class='my-path'></path>
<path d='M14.6437 2.05426C11.9803 1.2966 9.01686 1.64245 6.50315 3.25548C1.85499 6.23817 0.504864 12.4242 3.48756 17.0724C6.47025 21.7205 12.6563 23.0706 17.3044 20.088C20.4971 18.0393 22.1338 14.4793 21.8792 10.9444' stroke='stroke-current' stroke-width='1.4' stroke-linecap='round' className='my-path'></path>
</g>
<defs>
<clipPath id='clip0_9023_61563'>

View File

@@ -41,7 +41,7 @@ export default function DashboardPage() {
<div className='inline-block' role='status' aria-label='loading'>
<svg className='w-6 h-6 stroke-white animate-spin ' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'>
<g clip-path='url(#clip0_9023_61563)'>
<path d='M14.6437 2.05426C11.9803 1.2966 9.01686 1.64245 6.50315 3.25548C1.85499 6.23817 0.504864 12.4242 3.48756 17.0724C6.47025 21.7205 12.6563 23.0706 17.3044 20.088C20.4971 18.0393 22.1338 14.4793 21.8792 10.9444' stroke='stroke-current' stroke-width='1.4' stroke-linecap='round' class='my-path'></path>
<path d='M14.6437 2.05426C11.9803 1.2966 9.01686 1.64245 6.50315 3.25548C1.85499 6.23817 0.504864 12.4242 3.48756 17.0724C6.47025 21.7205 12.6563 23.0706 17.3044 20.088C20.4971 18.0393 22.1338 14.4793 21.8792 10.9444' stroke='stroke-current' stroke-width='1.4' stroke-linecap='round' className='my-path'></path>
</g>
<defs>
<clipPath id='clip0_9023_61563'>

View File

@@ -1,6 +1,6 @@
"use client";
import { AppSidebar } from "@/components/app-sidebar"
import { AppSidebar } from "@/components/app-sidebar";
import {
Breadcrumb,
BreadcrumbItem,
@@ -8,15 +8,15 @@ import {
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from "@/components/ui/breadcrumb"
import { Separator } from "@/components/ui/separator"
} from "@/components/ui/breadcrumb";
import { Separator } from "@/components/ui/separator";
import {
SidebarInset,
SidebarProvider,
SidebarTrigger,
} from "@/components/ui/sidebar"
import { Button } from "@/components/ui/button"
import { Plus, Link, MonitorCog, FileDigit, Trash2, LayoutGrid, List, Pencil, Cpu, Microchip, MemoryStick, HardDrive } from "lucide-react"
} from "@/components/ui/sidebar";
import { Button } from "@/components/ui/button";
import { Plus, Link, MonitorCog, FileDigit, Trash2, LayoutGrid, List, Pencil, Cpu, Microchip, MemoryStick, HardDrive } from "lucide-react";
import {
Card,
CardContent,
@@ -24,7 +24,7 @@ import {
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card"
} from "@/components/ui/card";
import {
Pagination,
PaginationContent,
@@ -33,7 +33,7 @@ import {
PaginationLink,
PaginationNext,
PaginationPrevious,
} from "@/components/ui/pagination"
} from "@/components/ui/pagination";
import {
AlertDialog,
AlertDialogAction,
@@ -44,55 +44,70 @@ import {
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
} from "@/components/ui/alert-dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip"
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
import Cookies from "js-cookie";
import { useState, useEffect } from "react";
import axios from 'axios';
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
interface Server {
id: number;
name: string;
os?: string;
ip?: string;
url?: string;
cpu?: string;
gpu?: string;
ram?: string;
disk?: string;
}
interface GetServersResponse {
servers: Server[];
maxPage: number;
}
export default function Dashboard() {
const [name, setName] = useState("");
const [os, setOs] = useState("");
const [ip, setIp] = useState("");
const [url, setUrl] = useState("");
const [cpu, setCpu] = useState("");
const [gpu, setGpu] = useState("");
const [ram, setRam] = useState("");
const [disk, setDisk] = useState("");
const [currentPage, setCurrentPage] = useState(1);
const [maxPage, setMaxPage] = useState(1);
const [servers, setServers] = useState([]);
const [isGridLayout, setIsGridLayout] = useState(false);
const [loading, setLoading] = useState(true);
const [name, setName] = useState<string>("");
const [os, setOs] = useState<string>("");
const [ip, setIp] = useState<string>("");
const [url, setUrl] = useState<string>("");
const [cpu, setCpu] = useState<string>("");
const [gpu, setGpu] = useState<string>("");
const [ram, setRam] = useState<string>("");
const [disk, setDisk] = useState<string>("");
const [currentPage, setCurrentPage] = useState<number>(1);
const [maxPage, setMaxPage] = useState<number>(1);
const [servers, setServers] = useState<Server[]>([]);
const [isGridLayout, setIsGridLayout] = useState<boolean>(false);
const [loading, setLoading] = useState<boolean>(true);
const [editId, setEditId] = useState<number | null>(null);
const [editName, setEditName] = useState("");
const [editOs, setEditOs] = useState("");
const [editIp, setEditIp] = useState("");
const [editUrl, setEditUrl] = useState("");
const [editCpu, setEditCpu] = useState("");
const [editGpu, setEditGpu] = useState("");
const [editRam, setEditRam] = useState("");
const [editDisk, setEditDisk] = useState("");
const [editName, setEditName] = useState<string>("");
const [editOs, setEditOs] = useState<string>("");
const [editIp, setEditIp] = useState<string>("");
const [editUrl, setEditUrl] = useState<string>("");
const [editCpu, setEditCpu] = useState<string>("");
const [editGpu, setEditGpu] = useState<string>("");
const [editRam, setEditRam] = useState<string>("");
const [editDisk, setEditDisk] = useState<string>("");
useEffect(() => {
const savedLayout = Cookies.get('layoutPreference-servers');
setIsGridLayout(savedLayout === 'grid');
@@ -110,7 +125,16 @@ export default function Dashboard() {
const add = async () => {
try {
const response = await axios.post('/api/servers/add', { name, os, ip, url, cpu, gpu, ram, disk });
await axios.post('/api/servers/add', {
name,
os,
ip,
url,
cpu,
gpu,
ram,
disk
});
getServers();
} catch (error: any) {
console.log(error.response.data);
@@ -120,9 +144,10 @@ export default function Dashboard() {
const getServers = async () => {
try {
setLoading(true);
const response = await axios.post('/api/servers/get', { page: currentPage });
const response = await axios.post<GetServersResponse>('/api/servers/get', {
page: currentPage
});
setServers(response.data.servers);
console.log(response.data.servers)
setMaxPage(response.data.maxPage);
setLoading(false);
} catch (error: any) {
@@ -151,19 +176,21 @@ export default function Dashboard() {
}
}
const openEditDialog = (server: any) => {
const openEditDialog = (server: Server) => {
setEditId(server.id);
setEditName(server.name);
setEditOs(server.os);
setEditIp(server.ip);
setEditUrl(server.url);
setEditCpu(server.cpu);
setEditGpu(server.gpu);
setEditRam(server.ram);
setEditDisk(server.disk);
setEditOs(server.os || "");
setEditIp(server.ip || "");
setEditUrl(server.url || "");
setEditCpu(server.cpu || "");
setEditGpu(server.gpu || "");
setEditRam(server.ram || "");
setEditDisk(server.disk || "");
};
const edit = async () => {
if (!editId) return;
try {
await axios.put('/api/servers/edit', {
id: editId,
@@ -507,7 +534,7 @@ export default function Dashboard() {
<div className='inline-block' role='status' aria-label='loading'>
<svg className='w-6 h-6 stroke-white animate-spin ' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'>
<g clip-path='url(#clip0_9023_61563)'>
<path d='M14.6437 2.05426C11.9803 1.2966 9.01686 1.64245 6.50315 3.25548C1.85499 6.23817 0.504864 12.4242 3.48756 17.0724C6.47025 21.7205 12.6563 23.0706 17.3044 20.088C20.4971 18.0393 22.1338 14.4793 21.8792 10.9444' stroke='stroke-current' stroke-width='1.4' stroke-linecap='round' class='my-path'></path>
<path d='M14.6437 2.05426C11.9803 1.2966 9.01686 1.64245 6.50315 3.25548C1.85499 6.23817 0.504864 12.4242 3.48756 17.0724C6.47025 21.7205 12.6563 23.0706 17.3044 20.088C20.4971 18.0393 22.1338 14.4793 21.8792 10.9444' stroke='stroke-current' stroke-width='1.4' stroke-linecap='round' className='my-path'></path>
</g>
<defs>
<clipPath id='clip0_9023_61563'>

View File

@@ -41,7 +41,7 @@ export default function DashboardPage() {
<div className='inline-block' role='status' aria-label='loading'>
<svg className='w-6 h-6 stroke-white animate-spin ' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'>
<g clip-path='url(#clip0_9023_61563)'>
<path d='M14.6437 2.05426C11.9803 1.2966 9.01686 1.64245 6.50315 3.25548C1.85499 6.23817 0.504864 12.4242 3.48756 17.0724C6.47025 21.7205 12.6563 23.0706 17.3044 20.088C20.4971 18.0393 22.1338 14.4793 21.8792 10.9444' stroke='stroke-current' stroke-width='1.4' stroke-linecap='round' class='my-path'></path>
<path d='M14.6437 2.05426C11.9803 1.2966 9.01686 1.64245 6.50315 3.25548C1.85499 6.23817 0.504864 12.4242 3.48756 17.0724C6.47025 21.7205 12.6563 23.0706 17.3044 20.088C20.4971 18.0393 22.1338 14.4793 21.8792 10.9444' stroke='stroke-current' stroke-width='1.4' stroke-linecap='round' className='my-path'></path>
</g>
<defs>
<clipPath id='clip0_9023_61563'>

View File

@@ -1,29 +1,29 @@
import { AppSidebar } from "@/components/app-sidebar"
import { AppSidebar } from "@/components/app-sidebar";
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from "@/components/ui/breadcrumb"
import { Separator } from "@/components/ui/separator"
} from "@/components/ui/breadcrumb";
import { Separator } from "@/components/ui/separator";
import {
SidebarInset,
SidebarProvider,
SidebarTrigger,
} from "@/components/ui/sidebar"
import { Card, CardHeader } from "@/components/ui/card"
import { useTheme } from "next-themes"
} from "@/components/ui/sidebar";
import { Card, CardHeader } from "@/components/ui/card";
import { useTheme } from "next-themes";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
} from "@/components/ui/select";
export default function Settings() {
const { theme, setTheme } = useTheme()
const { theme, setTheme } = useTheme();
return (
<SidebarProvider>
@@ -56,10 +56,13 @@ export default function Settings() {
<Card className="w-full mb-4 relative">
<CardHeader>
<span className="text-xl font-bold">Theme</span>
<Select value={theme} onValueChange={setTheme}>
<Select
value={theme}
onValueChange={(value: string) => setTheme(value)}
>
<SelectTrigger className="w-full [&_svg]:hidden">
<SelectValue>
{theme?.charAt(0).toUpperCase() + theme?.slice(1)}
{(theme ?? 'system').charAt(0).toUpperCase() + (theme ?? 'system').slice(1)}
</SelectValue>
</SelectTrigger>
<SelectContent>
@@ -74,5 +77,5 @@ export default function Settings() {
</div>
</SidebarInset>
</SidebarProvider>
)
);
}

View File

@@ -41,7 +41,7 @@ export default function DashboardPage() {
<div className='inline-block' role='status' aria-label='loading'>
<svg className='w-6 h-6 stroke-white animate-spin ' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'>
<g clip-path='url(#clip0_9023_61563)'>
<path d='M14.6437 2.05426C11.9803 1.2966 9.01686 1.64245 6.50315 3.25548C1.85499 6.23817 0.504864 12.4242 3.48756 17.0724C6.47025 21.7205 12.6563 23.0706 17.3044 20.088C20.4971 18.0393 22.1338 14.4793 21.8792 10.9444' stroke='stroke-current' stroke-width='1.4' stroke-linecap='round' class='my-path'></path>
<path d='M14.6437 2.05426C11.9803 1.2966 9.01686 1.64245 6.50315 3.25548C1.85499 6.23817 0.504864 12.4242 3.48756 17.0724C6.47025 21.7205 12.6563 23.0706 17.3044 20.088C20.4971 18.0393 22.1338 14.4793 21.8792 10.9444' stroke='stroke-current' stroke-width='1.4' stroke-linecap='round' className='my-path'></path>
</g>
<defs>
<clipPath id='clip0_9023_61563'>