mirror of
https://github.com/community-scripts/ProxmoxVE.git
synced 2025-02-01 14:31:50 +00:00
add popup, table & chart
This commit is contained in:
parent
e2b548a7c3
commit
a38e9070ef
@ -166,7 +166,7 @@ const DataFetcher: React.FC = () => {
|
|||||||
{showChart ? "Hide Chart" : "Show Chart"}
|
{showChart ? "Hide Chart" : "Show Chart"}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{showChart && <ApplicationChart data={filteredData} />}
|
<ApplicationChart data={filteredData} />
|
||||||
<div className="mb-4 flex justify-between items-center">
|
<div className="mb-4 flex justify-between items-center">
|
||||||
<p className="text-lg font-bold">{filteredData.length} results found</p>
|
<p className="text-lg font-bold">{filteredData.length} results found</p>
|
||||||
<select value={itemsPerPage} onChange={handleItemsPerPageChange} className="p-2 border">
|
<select value={itemsPerPage} onChange={handleItemsPerPageChange} className="p-2 border">
|
||||||
|
@ -3,7 +3,8 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { Pie } from "react-chartjs-2";
|
import { Pie } from "react-chartjs-2";
|
||||||
import { Chart as ChartJS, ArcElement, Tooltip, Legend } from "chart.js";
|
import { Chart as ChartJS, ArcElement, Tooltip, Legend } from "chart.js";
|
||||||
import ChartDataLabels from "chartjs-plugin-datalabels";
|
import ChartDataLabels from "chartjs-plugin-datalabels";
|
||||||
|
import Modal from "@/components/Modal";
|
||||||
|
|
||||||
ChartJS.register(ArcElement, Tooltip, Legend, ChartDataLabels);
|
ChartJS.register(ArcElement, Tooltip, Legend, ChartDataLabels);
|
||||||
|
|
||||||
@ -12,6 +13,8 @@ interface ApplicationChartProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ApplicationChart: React.FC<ApplicationChartProps> = ({ data }) => {
|
const ApplicationChart: React.FC<ApplicationChartProps> = ({ data }) => {
|
||||||
|
const [isChartOpen, setIsChartOpen] = useState(false);
|
||||||
|
const [isTableOpen, setIsTableOpen] = useState(false);
|
||||||
const [chartStartIndex, setChartStartIndex] = useState(0);
|
const [chartStartIndex, setChartStartIndex] = useState(0);
|
||||||
|
|
||||||
const appCounts: Record<string, number> = {};
|
const appCounts: Record<string, number> = {};
|
||||||
@ -42,40 +45,74 @@ const ApplicationChart: React.FC<ApplicationChartProps> = ({ data }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mt-6 text-center">
|
<div className="mt-6 text-center">
|
||||||
<div className="w-1/2 mx-auto my-6">
|
<button
|
||||||
<Pie
|
onClick={() => setIsChartOpen(true)}
|
||||||
data={chartData}
|
className="m-2 p-2 bg-blue-500 text-white rounded"
|
||||||
options={{
|
>
|
||||||
plugins: {
|
📊 Open Chart
|
||||||
legend: { display: false },
|
</button>
|
||||||
datalabels: {
|
<button
|
||||||
color: "white",
|
onClick={() => setIsTableOpen(true)}
|
||||||
font: { weight: "bold" },
|
className="m-2 p-2 bg-green-500 text-white rounded"
|
||||||
formatter: (value, context) => {
|
>
|
||||||
return context.chart.data.labels?.[context.dataIndex] || "";
|
📋 Open Table
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<Modal isOpen={isChartOpen} onClose={() => setIsChartOpen(false)}>
|
||||||
|
<h2 className="text-xl font-bold mb-4">Top Applications (Chart)</h2>
|
||||||
|
<div className="w-3/4 mx-auto">
|
||||||
|
<Pie
|
||||||
|
data={chartData}
|
||||||
|
options={{
|
||||||
|
plugins: {
|
||||||
|
legend: { display: false },
|
||||||
|
datalabels: {
|
||||||
|
color: "white",
|
||||||
|
font: { weight: "bold" },
|
||||||
|
formatter: (value, context) =>
|
||||||
|
context.chart.data.labels?.[context.dataIndex] || "",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}}
|
||||||
}}
|
/>
|
||||||
/>
|
</div>
|
||||||
</div>
|
<div className="flex justify-center space-x-4 mt-4">
|
||||||
|
<button
|
||||||
|
onClick={() => setChartStartIndex(Math.max(0, chartStartIndex - 20))}
|
||||||
|
disabled={chartStartIndex === 0}
|
||||||
|
className="p-2 border rounded bg-blue-500 text-white"
|
||||||
|
>
|
||||||
|
◀ Vorherige 20
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => setChartStartIndex(chartStartIndex + 20)}
|
||||||
|
disabled={chartStartIndex + 20 >= sortedApps.length}
|
||||||
|
className="p-2 border rounded bg-blue-500 text-white"
|
||||||
|
>
|
||||||
|
Nächste 20 ▶
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
<div className="flex justify-center space-x-4">
|
<Modal isOpen={isTableOpen} onClose={() => setIsTableOpen(false)}>
|
||||||
<button
|
<h2 className="text-xl font-bold mb-4">Application Count Table</h2>
|
||||||
onClick={() => setChartStartIndex(Math.max(0, chartStartIndex - 20))}
|
<table className="w-full border-collapse border border-gray-600">
|
||||||
disabled={chartStartIndex === 0}
|
<thead>
|
||||||
className={`p-2 border rounded ${chartStartIndex === 0 ? "bg-gray-400 cursor-not-allowed" : "bg-blue-500 text-white"}`}
|
<tr className="bg-gray-800 text-white">
|
||||||
>
|
<th className="p-2 border">Application</th>
|
||||||
◀ Last 20
|
<th className="p-2 border">Count</th>
|
||||||
</button>
|
</tr>
|
||||||
<button
|
</thead>
|
||||||
onClick={() => setChartStartIndex(chartStartIndex + 20)}
|
<tbody>
|
||||||
disabled={chartStartIndex + 20 >= sortedApps.length}
|
{sortedApps.map(([name, count]) => (
|
||||||
className={`p-2 border rounded ${chartStartIndex + 20 >= sortedApps.length ? "bg-gray-400 cursor-not-allowed" : "bg-blue-500 text-white"}`}
|
<tr key={name} className="hover:bg-gray-200">
|
||||||
>
|
<td className="p-2 border">{name}</td>
|
||||||
Next 20 ▶
|
<td className="p-2 border">{count}</td>
|
||||||
</button>
|
</tr>
|
||||||
</div>
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</Modal>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
29
frontend/src/components/Modal.tsx
Normal file
29
frontend/src/components/Modal.tsx
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
interface ModalProps {
|
||||||
|
isOpen: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
children: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Modal: React.FC<ModalProps> = ({ isOpen, onClose, children }) => {
|
||||||
|
if (!isOpen) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="fixed inset-0 bg-black bg-opacity-50 flex justify-center items-center z-50">
|
||||||
|
<div className="bg-white p-6 rounded-lg shadow-lg w-3/4 max-w-4xl relative">
|
||||||
|
<button
|
||||||
|
onClick={onClose}
|
||||||
|
className="absolute top-2 right-2 bg-red-500 text-white p-1 rounded"
|
||||||
|
>
|
||||||
|
✖
|
||||||
|
</button>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Modal;
|
Loading…
x
Reference in New Issue
Block a user