mirror of
https://github.com/9technologygroup/patchmon.net.git
synced 2025-11-10 17:05:48 +00:00
fix(frontend): add missing explicit types for button elems
This commit is contained in:
@@ -75,6 +75,7 @@ const SortableCardItem = ({ card, onToggle }) => {
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onToggle(card.cardId)}
|
||||
className={`flex items-center gap-1 px-2 py-1 rounded text-xs font-medium transition-colors ${
|
||||
card.enabled
|
||||
@@ -271,6 +272,7 @@ const DashboardSettingsModal = ({ isOpen, onClose }) => {
|
||||
</h3>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className="text-secondary-400 hover:text-secondary-600 dark:text-secondary-500 dark:hover:text-secondary-300"
|
||||
>
|
||||
@@ -314,6 +316,7 @@ const DashboardSettingsModal = ({ isOpen, onClose }) => {
|
||||
|
||||
<div className="bg-secondary-50 dark:bg-secondary-700 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleSave}
|
||||
disabled={!hasChanges || updatePreferencesMutation.isPending}
|
||||
className={`w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 text-base font-medium text-white sm:ml-3 sm:w-auto sm:text-sm ${
|
||||
@@ -336,6 +339,7 @@ const DashboardSettingsModal = ({ isOpen, onClose }) => {
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleReset}
|
||||
className="mt-3 w-full inline-flex justify-center rounded-md border border-secondary-300 dark:border-secondary-600 shadow-sm px-4 py-2 bg-white dark:bg-secondary-800 text-base font-medium text-secondary-700 dark:text-secondary-200 hover:bg-secondary-50 dark:hover:bg-secondary-700 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"
|
||||
>
|
||||
@@ -344,6 +348,7 @@ const DashboardSettingsModal = ({ isOpen, onClose }) => {
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className="mt-3 w-full inline-flex justify-center rounded-md border border-secondary-300 dark:border-secondary-600 shadow-sm px-4 py-2 bg-white dark:bg-secondary-800 text-base font-medium text-secondary-700 dark:text-secondary-200 hover:bg-secondary-50 dark:hover:bg-secondary-700 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"
|
||||
>
|
||||
|
||||
@@ -102,6 +102,7 @@ const InlineEdit = ({
|
||||
} ${isLoading ? "opacity-50" : ""}`}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleSave}
|
||||
disabled={isLoading || editValue.trim() === ""}
|
||||
className="p-1 text-green-600 hover:text-green-700 hover:bg-green-50 dark:hover:bg-green-900/20 rounded transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
@@ -110,6 +111,7 @@ const InlineEdit = ({
|
||||
<Check className="h-4 w-4" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleCancel}
|
||||
disabled={isLoading}
|
||||
className="p-1 text-red-600 hover:text-red-700 hover:bg-red-50 dark:hover:bg-red-900/20 rounded transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
@@ -145,6 +147,7 @@ const InlineEdit = ({
|
||||
{displayValue}
|
||||
{!disabled && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleEdit}
|
||||
className="p-1 text-secondary-400 hover:text-secondary-600 dark:hover:text-secondary-300 hover:bg-secondary-100 dark:hover:bg-secondary-700 rounded transition-colors opacity-0 group-hover:opacity-100"
|
||||
title="Edit"
|
||||
|
||||
@@ -221,6 +221,7 @@ const InlineGroupEdit = ({
|
||||
)}
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleSave}
|
||||
disabled={isLoading}
|
||||
className="p-1 text-green-600 hover:text-green-700 hover:bg-green-50 dark:hover:bg-green-900/20 rounded transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
@@ -229,6 +230,7 @@ const InlineGroupEdit = ({
|
||||
<Check className="h-4 w-4" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleCancel}
|
||||
disabled={isLoading}
|
||||
className="p-1 text-red-600 hover:text-red-700 hover:bg-red-50 dark:hover:bg-red-900/20 rounded transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
@@ -256,6 +258,7 @@ const InlineGroupEdit = ({
|
||||
</span>
|
||||
{!disabled && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleEdit}
|
||||
className="p-1 text-secondary-400 hover:text-secondary-600 dark:hover:text-secondary-300 hover:bg-secondary-100 dark:hover:bg-secondary-700 rounded transition-colors opacity-0 group-hover:opacity-100"
|
||||
title="Edit group"
|
||||
|
||||
@@ -386,6 +386,7 @@ const Layout = ({ children }) => {
|
||||
{subItem.name}
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
setSidebarOpen(false);
|
||||
@@ -453,6 +454,7 @@ const Layout = ({ children }) => {
|
||||
>
|
||||
{sidebarCollapsed ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setSidebarCollapsed(!sidebarCollapsed)}
|
||||
className="flex items-center justify-center w-8 h-8 rounded-md hover:bg-secondary-100 transition-colors"
|
||||
title="Expand sidebar"
|
||||
@@ -468,6 +470,7 @@ const Layout = ({ children }) => {
|
||||
</h1>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setSidebarCollapsed(!sidebarCollapsed)}
|
||||
className="flex items-center justify-center w-8 h-8 rounded-md hover:bg-secondary-100 transition-colors"
|
||||
title="Collapse sidebar"
|
||||
@@ -549,6 +552,7 @@ const Layout = ({ children }) => {
|
||||
)}
|
||||
{!sidebarCollapsed && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
handleAddHost();
|
||||
@@ -659,6 +663,7 @@ const Layout = ({ children }) => {
|
||||
</div>
|
||||
</Link>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleLogout}
|
||||
className="ml-2 p-1.5 text-secondary-400 hover:text-secondary-600 hover:bg-secondary-100 rounded transition-colors"
|
||||
title="Sign out"
|
||||
@@ -675,6 +680,7 @@ const Layout = ({ children }) => {
|
||||
Updated: {formatRelativeTimeShort(stats.lastUpdated)}
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => refetch()}
|
||||
disabled={isFetching}
|
||||
className="p-1 hover:bg-secondary-100 dark:hover:bg-secondary-700 rounded flex-shrink-0 disabled:opacity-50"
|
||||
@@ -707,6 +713,7 @@ const Layout = ({ children }) => {
|
||||
<UserCircle className="h-5 w-5" />
|
||||
</Link>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleLogout}
|
||||
className="flex items-center justify-center w-full p-2 text-secondary-400 hover:text-secondary-600 hover:bg-secondary-100 dark:hover:bg-secondary-700 rounded-md transition-colors"
|
||||
title="Sign out"
|
||||
@@ -717,6 +724,7 @@ const Layout = ({ children }) => {
|
||||
{stats && (
|
||||
<div className="flex flex-col items-center py-1 border-t border-secondary-200 dark:border-secondary-700">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => refetch()}
|
||||
disabled={isFetching}
|
||||
className="p-1 hover:bg-secondary-100 dark:hover:bg-secondary-700 rounded disabled:opacity-50"
|
||||
|
||||
@@ -831,6 +831,7 @@ const Dashboard = () => {
|
||||
{error.message || "Failed to load dashboard statistics"}
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => refetch()}
|
||||
className="mt-2 btn-danger text-xs"
|
||||
>
|
||||
@@ -1010,6 +1011,7 @@ const Dashboard = () => {
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowSettingsModal(true)}
|
||||
className="btn-outline flex items-center gap-2"
|
||||
title="Customize dashboard layout"
|
||||
@@ -1018,6 +1020,7 @@ const Dashboard = () => {
|
||||
Customize Dashboard
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => refetch()}
|
||||
disabled={isFetching}
|
||||
className="btn-outline flex items-center gap-2"
|
||||
|
||||
@@ -163,6 +163,7 @@ const HostDetail = () => {
|
||||
{error.message || "Failed to load host details"}
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => refetch()}
|
||||
className="mt-2 btn-danger text-xs"
|
||||
>
|
||||
@@ -257,6 +258,7 @@ const HostDetail = () => {
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => refetch()}
|
||||
disabled={isFetching}
|
||||
className="btn-outline flex items-center gap-2 text-sm"
|
||||
@@ -268,6 +270,7 @@ const HostDetail = () => {
|
||||
{isFetching ? "Refreshing..." : "Refresh"}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowCredentialsModal(true)}
|
||||
className="btn-outline flex items-center gap-2 text-sm"
|
||||
>
|
||||
@@ -275,6 +278,7 @@ const HostDetail = () => {
|
||||
Deploy Agent
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowDeleteModal(true)}
|
||||
className="btn-danger flex items-center gap-2 text-sm"
|
||||
>
|
||||
@@ -292,6 +296,7 @@ const HostDetail = () => {
|
||||
<div className="card">
|
||||
<div className="flex border-b border-secondary-200 dark:border-secondary-600">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleTabChange("host")}
|
||||
className={`px-4 py-2 text-sm font-medium ${
|
||||
activeTab === "host"
|
||||
@@ -302,6 +307,7 @@ const HostDetail = () => {
|
||||
Host Info
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleTabChange("network")}
|
||||
className={`px-4 py-2 text-sm font-medium ${
|
||||
activeTab === "network"
|
||||
@@ -312,6 +318,7 @@ const HostDetail = () => {
|
||||
Network
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleTabChange("system")}
|
||||
className={`px-4 py-2 text-sm font-medium ${
|
||||
activeTab === "system"
|
||||
@@ -322,6 +329,7 @@ const HostDetail = () => {
|
||||
System
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleTabChange("monitoring")}
|
||||
className={`px-4 py-2 text-sm font-medium ${
|
||||
activeTab === "monitoring"
|
||||
@@ -332,6 +340,7 @@ const HostDetail = () => {
|
||||
Resource
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleTabChange("history")}
|
||||
className={`px-4 py-2 text-sm font-medium ${
|
||||
activeTab === "history"
|
||||
@@ -427,6 +436,7 @@ const HostDetail = () => {
|
||||
Auto-update
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
toggleAutoUpdateMutation.mutate(!host.auto_update)
|
||||
}
|
||||
@@ -862,6 +872,7 @@ const HostDetail = () => {
|
||||
{host.update_history.length > 5 && (
|
||||
<div className="px-4 py-2 border-t border-secondary-200 dark:border-secondary-600 bg-secondary-50 dark:bg-secondary-700">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowAllUpdates(!showAllUpdates)}
|
||||
className="flex items-center gap-1.5 text-xs text-primary-600 hover:text-primary-700 dark:text-primary-400 dark:hover:text-primary-300 font-medium"
|
||||
>
|
||||
@@ -906,6 +917,7 @@ const HostDetail = () => {
|
||||
<div className="p-4">
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => navigate(`/packages?host=${hostId}`)}
|
||||
className="text-center p-4 bg-primary-50 dark:bg-primary-900/20 rounded-lg hover:bg-primary-100 dark:hover:bg-primary-900/30 transition-colors group"
|
||||
title="View all packages for this host"
|
||||
@@ -922,6 +934,7 @@ const HostDetail = () => {
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => navigate(`/packages?host=${hostId}`)}
|
||||
className="text-center p-4 bg-warning-50 dark:bg-warning-900/20 rounded-lg hover:bg-warning-100 dark:hover:bg-warning-900/30 transition-colors group"
|
||||
title="View outdated packages for this host"
|
||||
@@ -938,6 +951,7 @@ const HostDetail = () => {
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
navigate(`/packages?host=${hostId}&filter=security`)
|
||||
}
|
||||
@@ -1083,6 +1097,7 @@ echo " - View logs: tail -f /var/log/patchmon-agent.log"`;
|
||||
Host Setup - {host.friendly_name}
|
||||
</h3>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className="text-secondary-400 hover:text-secondary-600 dark:text-secondary-500 dark:hover:text-secondary-300"
|
||||
>
|
||||
@@ -1094,6 +1109,7 @@ echo " - View logs: tail -f /var/log/patchmon-agent.log"`;
|
||||
<div className="border-b border-secondary-200 dark:border-secondary-600 mb-6">
|
||||
<nav className="-mb-px flex space-x-8">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setActiveTab("quick-install")}
|
||||
className={`py-2 px-1 border-b-2 font-medium text-sm ${
|
||||
activeTab === "quick-install"
|
||||
@@ -1104,6 +1120,7 @@ echo " - View logs: tail -f /var/log/patchmon-agent.log"`;
|
||||
Quick Install
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setActiveTab("credentials")}
|
||||
className={`py-2 px-1 border-b-2 font-medium text-sm ${
|
||||
activeTab === "credentials"
|
||||
@@ -1135,6 +1152,7 @@ echo " - View logs: tail -f /var/log/patchmon-agent.log"`;
|
||||
className="flex-1 px-3 py-2 border border-primary-300 dark:border-primary-600 rounded-md bg-white dark:bg-secondary-800 text-sm font-mono text-secondary-900 dark:text-white"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
copyToClipboard(
|
||||
`curl -s ${serverUrl}/api/v1/hosts/install | bash -s -- ${serverUrl} "${host.api_id}" "${host.api_key}"`,
|
||||
@@ -1168,6 +1186,7 @@ echo " - View logs: tail -f /var/log/patchmon-agent.log"`;
|
||||
className="flex-1 px-3 py-2 border border-secondary-300 dark:border-secondary-600 rounded-md bg-white dark:bg-secondary-800 text-sm font-mono text-secondary-900 dark:text-white"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
copyToClipboard(
|
||||
`curl -o /tmp/patchmon-agent.sh ${serverUrl}/api/v1/hosts/agent/download`,
|
||||
@@ -1193,6 +1212,7 @@ echo " - View logs: tail -f /var/log/patchmon-agent.log"`;
|
||||
className="flex-1 px-3 py-2 border border-secondary-300 dark:border-secondary-600 rounded-md bg-white dark:bg-secondary-800 text-sm font-mono text-secondary-900 dark:text-white"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
copyToClipboard(
|
||||
"sudo mkdir -p /etc/patchmon && sudo mv /tmp/patchmon-agent.sh /usr/local/bin/patchmon-agent.sh && sudo chmod +x /usr/local/bin/patchmon-agent.sh",
|
||||
@@ -1218,6 +1238,7 @@ echo " - View logs: tail -f /var/log/patchmon-agent.log"`;
|
||||
className="flex-1 px-3 py-2 border border-secondary-300 dark:border-secondary-600 rounded-md bg-white dark:bg-secondary-800 text-sm font-mono text-secondary-900 dark:text-white"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
copyToClipboard(
|
||||
`sudo /usr/local/bin/patchmon-agent.sh configure "${host.api_id}" "${host.api_key}"`,
|
||||
@@ -1243,6 +1264,7 @@ echo " - View logs: tail -f /var/log/patchmon-agent.log"`;
|
||||
className="flex-1 px-3 py-2 border border-secondary-300 dark:border-secondary-600 rounded-md bg-white dark:bg-secondary-800 text-sm font-mono text-secondary-900 dark:text-white"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
copyToClipboard(
|
||||
"sudo /usr/local/bin/patchmon-agent.sh test",
|
||||
@@ -1268,6 +1290,7 @@ echo " - View logs: tail -f /var/log/patchmon-agent.log"`;
|
||||
className="flex-1 px-3 py-2 border border-secondary-300 dark:border-secondary-600 rounded-md bg-white dark:bg-secondary-800 text-sm font-mono text-secondary-900 dark:text-white"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
copyToClipboard(
|
||||
"sudo /usr/local/bin/patchmon-agent.sh update",
|
||||
@@ -1293,6 +1316,7 @@ echo " - View logs: tail -f /var/log/patchmon-agent.log"`;
|
||||
className="flex-1 px-3 py-2 border border-secondary-300 dark:border-secondary-600 rounded-md bg-white dark:bg-secondary-800 text-sm font-mono text-secondary-900 dark:text-white"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
copyToClipboard(
|
||||
`echo "${new Date().getMinutes()} * * * * /usr/local/bin/patchmon-agent.sh update >/dev/null 2>&1" | sudo crontab -`,
|
||||
@@ -1329,6 +1353,7 @@ echo " - View logs: tail -f /var/log/patchmon-agent.log"`;
|
||||
className="flex-1 px-3 py-2 border border-secondary-300 dark:border-secondary-600 rounded-md bg-secondary-50 dark:bg-secondary-800 text-sm font-mono text-secondary-900 dark:text-white"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => copyToClipboard(host.api_id)}
|
||||
className="btn-outline flex items-center gap-1"
|
||||
>
|
||||
@@ -1350,6 +1375,7 @@ echo " - View logs: tail -f /var/log/patchmon-agent.log"`;
|
||||
className="flex-1 px-3 py-2 border border-secondary-300 dark:border-secondary-600 rounded-md bg-secondary-50 dark:bg-secondary-800 text-sm font-mono text-secondary-900 dark:text-white"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowApiKey(!showApiKey)}
|
||||
className="btn-outline flex items-center gap-1"
|
||||
>
|
||||
@@ -1360,6 +1386,7 @@ echo " - View logs: tail -f /var/log/patchmon-agent.log"`;
|
||||
)}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => copyToClipboard(host.api_key)}
|
||||
className="btn-outline flex items-center gap-1"
|
||||
>
|
||||
@@ -1389,7 +1416,7 @@ echo " - View logs: tail -f /var/log/patchmon-agent.log"`;
|
||||
)}
|
||||
|
||||
<div className="flex justify-end pt-6">
|
||||
<button onClick={onClose} className="btn-primary">
|
||||
<button type="button" onClick={onClose} className="btn-primary">
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
@@ -1441,6 +1468,7 @@ const DeleteConfirmationModal = ({
|
||||
|
||||
<div className="flex justify-end gap-3">
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className="btn-outline"
|
||||
disabled={isLoading}
|
||||
@@ -1448,6 +1476,7 @@ const DeleteConfirmationModal = ({
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onConfirm}
|
||||
className="btn-danger"
|
||||
disabled={isLoading}
|
||||
|
||||
@@ -126,6 +126,7 @@ const HostGroups = () => {
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowCreateModal(true)}
|
||||
className="btn-primary flex items-center gap-2"
|
||||
>
|
||||
@@ -161,6 +162,7 @@ const HostGroups = () => {
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleEdit(group)}
|
||||
className="p-1 text-secondary-400 hover:text-secondary-600 hover:bg-secondary-100 rounded"
|
||||
title="Edit group"
|
||||
@@ -168,6 +170,7 @@ const HostGroups = () => {
|
||||
<Edit className="h-4 w-4" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleDeleteClick(group)}
|
||||
className="p-1 text-secondary-400 hover:text-danger-600 hover:bg-danger-50 rounded"
|
||||
title="Delete group"
|
||||
@@ -199,6 +202,7 @@ const HostGroups = () => {
|
||||
Create your first host group to organize your hosts
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowCreateModal(true)}
|
||||
className="btn-primary flex items-center gap-2 mx-auto"
|
||||
>
|
||||
@@ -479,6 +483,7 @@ const DeleteHostGroupModal = ({ group, onClose, onConfirm, isLoading }) => {
|
||||
|
||||
<div className="flex justify-end gap-3">
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className="btn-outline"
|
||||
disabled={isLoading}
|
||||
@@ -486,6 +491,7 @@ const DeleteHostGroupModal = ({ group, onClose, onConfirm, isLoading }) => {
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onConfirm}
|
||||
className="btn-danger"
|
||||
disabled={isLoading || group._count.hosts > 0}
|
||||
|
||||
@@ -103,6 +103,7 @@ const AddHostModal = ({ isOpen, onClose, onSuccess }) => {
|
||||
Add New Host
|
||||
</h3>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className="text-secondary-400 hover:text-secondary-600 dark:text-secondary-500 dark:hover:text-secondary-300"
|
||||
>
|
||||
@@ -369,6 +370,7 @@ echo " - View logs: tail -f /var/log/patchmon-agent.log"`,
|
||||
Host Setup - {host.friendly_name}
|
||||
</h3>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className="text-secondary-400 hover:text-secondary-600"
|
||||
>
|
||||
@@ -379,6 +381,7 @@ echo " - View logs: tail -f /var/log/patchmon-agent.log"`,
|
||||
{/* Tabs */}
|
||||
<div className="flex space-x-1 mb-6 bg-secondary-100 p-1 rounded-lg">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setActiveTab("quick")}
|
||||
className={`px-4 py-2 rounded-md text-sm font-medium transition-colors ${
|
||||
activeTab === "quick"
|
||||
@@ -389,6 +392,7 @@ echo " - View logs: tail -f /var/log/patchmon-agent.log"`,
|
||||
Quick Install
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setActiveTab("credentials")}
|
||||
className={`px-4 py-2 rounded-md text-sm font-medium transition-colors ${
|
||||
activeTab === "credentials"
|
||||
@@ -399,6 +403,7 @@ echo " - View logs: tail -f /var/log/patchmon-agent.log"`,
|
||||
API Credentials
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setActiveTab("setup")}
|
||||
className={`px-4 py-2 rounded-md text-sm font-medium transition-colors ${
|
||||
activeTab === "setup"
|
||||
@@ -409,6 +414,7 @@ echo " - View logs: tail -f /var/log/patchmon-agent.log"`,
|
||||
Setup Instructions
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setActiveTab("script")}
|
||||
className={`px-4 py-2 rounded-md text-sm font-medium transition-colors ${
|
||||
activeTab === "script"
|
||||
@@ -444,6 +450,7 @@ echo " - View logs: tail -f /var/log/patchmon-agent.log"`,
|
||||
{commands.oneLine}
|
||||
</code>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
copyToClipboard(commands.oneLine, "Installation command")
|
||||
}
|
||||
@@ -512,6 +519,7 @@ echo " - View logs: tail -f /var/log/patchmon-agent.log"`,
|
||||
className="flex-1 block w-full border-secondary-300 rounded-l-md shadow-sm bg-secondary-50"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => copyToClipboard(host.apiId, "API ID")}
|
||||
className="px-3 py-2 border border-l-0 border-secondary-300 rounded-r-md bg-secondary-50 hover:bg-secondary-100"
|
||||
>
|
||||
@@ -532,6 +540,7 @@ echo " - View logs: tail -f /var/log/patchmon-agent.log"`,
|
||||
className="flex-1 block w-full border-secondary-300 rounded-l-md shadow-sm bg-secondary-50"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowApiKey(!showApiKey)}
|
||||
className="px-3 py-2 border border-l-0 border-r-0 border-secondary-300 bg-secondary-50 hover:bg-secondary-100"
|
||||
>
|
||||
@@ -542,6 +551,7 @@ echo " - View logs: tail -f /var/log/patchmon-agent.log"`,
|
||||
)}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => copyToClipboard(host.apiKey, "API Key")}
|
||||
className="px-3 py-2 border border-l-0 border-secondary-300 rounded-r-md bg-secondary-50 hover:bg-secondary-100"
|
||||
>
|
||||
@@ -586,6 +596,7 @@ echo " - View logs: tail -f /var/log/patchmon-agent.log"`,
|
||||
{commands.download}
|
||||
</code>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
copyToClipboard(commands.download, "Download commands")
|
||||
}
|
||||
@@ -606,6 +617,7 @@ echo " - View logs: tail -f /var/log/patchmon-agent.log"`,
|
||||
<div className="flex justify-between items-start">
|
||||
<code className="flex-1">{commands.configure}</code>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
copyToClipboard(commands.configure, "Configure command")
|
||||
}
|
||||
@@ -626,6 +638,7 @@ echo " - View logs: tail -f /var/log/patchmon-agent.log"`,
|
||||
<div className="flex justify-between items-start">
|
||||
<code className="flex-1">{commands.test}</code>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
copyToClipboard(commands.test, "Test command")
|
||||
}
|
||||
@@ -650,6 +663,7 @@ echo " - View logs: tail -f /var/log/patchmon-agent.log"`,
|
||||
<div className="flex justify-between items-start">
|
||||
<code className="flex-1">{commands.initialUpdate}</code>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
copyToClipboard(
|
||||
commands.initialUpdate,
|
||||
@@ -673,6 +687,7 @@ echo " - View logs: tail -f /var/log/patchmon-agent.log"`,
|
||||
<div className="flex justify-between items-start">
|
||||
<code className="flex-1">{commands.crontab}</code>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
copyToClipboard(commands.crontab, "Crontab command")
|
||||
}
|
||||
@@ -709,6 +724,7 @@ echo " - View logs: tail -f /var/log/patchmon-agent.log"`,
|
||||
Complete Setup Script
|
||||
</h5>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
copyToClipboard(commands.fullSetup, "Complete setup script")
|
||||
}
|
||||
@@ -750,6 +766,7 @@ echo " - View logs: tail -f /var/log/patchmon-agent.log"`,
|
||||
Download Agent Script
|
||||
</a>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className="px-4 py-2 text-sm font-medium text-secondary-700 bg-white border border-secondary-300 rounded-md hover:bg-secondary-50"
|
||||
>
|
||||
@@ -1270,6 +1287,7 @@ const Hosts = () => {
|
||||
case "select":
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleSelectHost(host.id)}
|
||||
className="flex items-center gap-2 hover:text-secondary-700"
|
||||
>
|
||||
@@ -1373,6 +1391,7 @@ const Hosts = () => {
|
||||
case "updates":
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => navigate(`/packages?host=${host.id}`)}
|
||||
className="text-sm text-primary-600 hover:text-primary-900 dark:text-primary-400 dark:hover:text-primary-300 font-medium hover:underline"
|
||||
title="View packages for this host"
|
||||
@@ -1472,6 +1491,7 @@ const Hosts = () => {
|
||||
{error.message || "Failed to load hosts"}
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => refetch()}
|
||||
className="mt-2 btn-danger text-xs"
|
||||
>
|
||||
@@ -1515,6 +1535,7 @@ const Hosts = () => {
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => refetch()}
|
||||
disabled={isFetching}
|
||||
className="btn-outline flex items-center gap-2"
|
||||
@@ -1526,6 +1547,7 @@ const Hosts = () => {
|
||||
{isFetching ? "Refreshing..." : "Refresh"}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowAddModal(true)}
|
||||
className="btn-primary flex items-center gap-2"
|
||||
>
|
||||
@@ -1615,6 +1637,7 @@ const Hosts = () => {
|
||||
{selectedHosts.length !== 1 ? "s" : ""} selected
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowBulkAssignModal(true)}
|
||||
className="btn-outline flex items-center gap-2"
|
||||
>
|
||||
@@ -1622,6 +1645,7 @@ const Hosts = () => {
|
||||
Assign to Group
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowBulkDeleteModal(true)}
|
||||
className="btn-danger flex items-center gap-2"
|
||||
>
|
||||
@@ -1629,6 +1653,7 @@ const Hosts = () => {
|
||||
Delete
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setSelectedHosts([])}
|
||||
className="text-sm text-secondary-500 hover:text-secondary-700"
|
||||
>
|
||||
@@ -1656,6 +1681,7 @@ const Hosts = () => {
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowFilters(!showFilters)}
|
||||
className={`btn-outline flex items-center gap-2 ${showFilters ? "bg-primary-50 border-primary-300" : ""}`}
|
||||
>
|
||||
@@ -1663,6 +1689,7 @@ const Hosts = () => {
|
||||
Filters
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowColumnSettings(true)}
|
||||
className="btn-outline flex items-center gap-2"
|
||||
>
|
||||
@@ -1683,6 +1710,7 @@ const Hosts = () => {
|
||||
<ChevronDown className="absolute right-1 top-1/2 transform -translate-y-1/2 h-4 w-4 text-secondary-400 dark:text-secondary-500 pointer-events-none" />
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setHideStale(!hideStale)}
|
||||
className={`btn-outline flex items-center gap-2 ${hideStale ? "bg-primary-50 border-primary-300" : ""}`}
|
||||
>
|
||||
@@ -1690,6 +1718,7 @@ const Hosts = () => {
|
||||
Hide Stale
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowAddModal(true)}
|
||||
className="btn-primary flex items-center gap-2"
|
||||
>
|
||||
@@ -1754,6 +1783,7 @@ const Hosts = () => {
|
||||
</div>
|
||||
<div className="flex items-end">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
setSearchTerm("");
|
||||
setGroupFilter("all");
|
||||
@@ -1819,6 +1849,7 @@ const Hosts = () => {
|
||||
>
|
||||
{column.id === "select" ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleSelectAll}
|
||||
className="flex items-center gap-2 hover:text-secondary-700"
|
||||
>
|
||||
@@ -1831,6 +1862,7 @@ const Hosts = () => {
|
||||
</button>
|
||||
) : column.id === "host" ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
handleSort("friendlyName")
|
||||
}
|
||||
@@ -1841,6 +1873,7 @@ const Hosts = () => {
|
||||
</button>
|
||||
) : column.id === "hostname" ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleSort("hostname")}
|
||||
className="flex items-center gap-2 hover:text-secondary-700"
|
||||
>
|
||||
@@ -1849,6 +1882,7 @@ const Hosts = () => {
|
||||
</button>
|
||||
) : column.id === "ip" ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleSort("ip")}
|
||||
className="flex items-center gap-2 hover:text-secondary-700"
|
||||
>
|
||||
@@ -1857,6 +1891,7 @@ const Hosts = () => {
|
||||
</button>
|
||||
) : column.id === "group" ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleSort("group")}
|
||||
className="flex items-center gap-2 hover:text-secondary-700"
|
||||
>
|
||||
@@ -1865,6 +1900,7 @@ const Hosts = () => {
|
||||
</button>
|
||||
) : column.id === "os" ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleSort("os")}
|
||||
className="flex items-center gap-2 hover:text-secondary-700"
|
||||
>
|
||||
@@ -1873,6 +1909,7 @@ const Hosts = () => {
|
||||
</button>
|
||||
) : column.id === "os_version" ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleSort("os_version")}
|
||||
className="flex items-center gap-2 hover:text-secondary-700"
|
||||
>
|
||||
@@ -1881,6 +1918,7 @@ const Hosts = () => {
|
||||
</button>
|
||||
) : column.id === "agent_version" ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
handleSort("agent_version")
|
||||
}
|
||||
@@ -1895,6 +1933,7 @@ const Hosts = () => {
|
||||
</div>
|
||||
) : column.id === "status" ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleSort("status")}
|
||||
className="flex items-center gap-2 hover:text-secondary-700"
|
||||
>
|
||||
@@ -1903,6 +1942,7 @@ const Hosts = () => {
|
||||
</button>
|
||||
) : column.id === "updates" ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleSort("updates")}
|
||||
className="flex items-center gap-2 hover:text-secondary-700"
|
||||
>
|
||||
@@ -1911,6 +1951,7 @@ const Hosts = () => {
|
||||
</button>
|
||||
) : column.id === "last_update" ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
handleSort("last_update")
|
||||
}
|
||||
@@ -2047,6 +2088,7 @@ const BulkAssignModal = ({
|
||||
Assign to Host Group
|
||||
</h3>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className="text-secondary-400 hover:text-secondary-600"
|
||||
>
|
||||
@@ -2135,6 +2177,7 @@ const BulkDeleteModal = ({
|
||||
Delete Hosts
|
||||
</h3>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className="text-secondary-400 hover:text-secondary-600 dark:text-secondary-500 dark:hover:text-secondary-300"
|
||||
disabled={isLoading}
|
||||
@@ -2236,6 +2279,7 @@ const ColumnSettingsModal = ({
|
||||
Column Settings
|
||||
</h3>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className="text-secondary-400 hover:text-secondary-600 dark:text-secondary-500 dark:hover:text-secondary-300"
|
||||
>
|
||||
@@ -2270,6 +2314,7 @@ const ColumnSettingsModal = ({
|
||||
</span>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onToggleVisibility(column.id)}
|
||||
className={`p-1 rounded ${
|
||||
column.visible
|
||||
@@ -2288,10 +2333,10 @@ const ColumnSettingsModal = ({
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between mt-6">
|
||||
<button onClick={onReset} className="btn-outline">
|
||||
<button type="button" onClick={onReset} className="btn-outline">
|
||||
Reset to Default
|
||||
</button>
|
||||
<button onClick={onClose} className="btn-primary">
|
||||
<button type="button" onClick={onClose} className="btn-primary">
|
||||
Done
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -143,6 +143,7 @@ const Options = () => {
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowCreateModal(true)}
|
||||
className="btn-primary flex items-center gap-2"
|
||||
>
|
||||
@@ -178,6 +179,7 @@ const Options = () => {
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleEdit(group)}
|
||||
className="p-1 text-secondary-400 hover:text-secondary-600 hover:bg-secondary-100 rounded"
|
||||
title="Edit group"
|
||||
@@ -185,6 +187,7 @@ const Options = () => {
|
||||
<Edit className="h-4 w-4" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleDeleteClick(group)}
|
||||
className="p-1 text-secondary-400 hover:text-danger-600 hover:bg-danger-50 rounded"
|
||||
title="Delete group"
|
||||
@@ -216,6 +219,7 @@ const Options = () => {
|
||||
Create your first host group to organize your hosts
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowCreateModal(true)}
|
||||
className="btn-primary flex items-center gap-2 mx-auto"
|
||||
>
|
||||
@@ -260,6 +264,7 @@ const Options = () => {
|
||||
const Icon = tab.icon;
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
key={tab.id}
|
||||
onClick={() => setActiveTab(tab.id)}
|
||||
className={`py-2 px-1 border-b-2 font-medium text-sm flex items-center gap-2 ${
|
||||
@@ -558,6 +563,7 @@ const DeleteHostGroupModal = ({ group, onClose, onConfirm, isLoading }) => {
|
||||
|
||||
<div className="flex justify-end gap-3">
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className="btn-outline"
|
||||
disabled={isLoading}
|
||||
@@ -565,6 +571,7 @@ const DeleteHostGroupModal = ({ group, onClose, onConfirm, isLoading }) => {
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onConfirm}
|
||||
className="btn-danger"
|
||||
disabled={isLoading || group._count.hosts > 0}
|
||||
|
||||
@@ -272,6 +272,7 @@ const Packages = () => {
|
||||
pkg.affectedHostsCount || pkg.affectedHosts?.length || 0;
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleAffectedHostsClick(pkg)}
|
||||
className="text-left hover:bg-secondary-100 dark:hover:bg-secondary-700 rounded p-1 -m-1 transition-colors group"
|
||||
title={`Click to view all ${affectedHostsCount} affected hosts`}
|
||||
@@ -354,6 +355,7 @@ const Packages = () => {
|
||||
{error.message || "Failed to load packages"}
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => refetch()}
|
||||
className="mt-2 btn-danger text-xs"
|
||||
>
|
||||
@@ -380,6 +382,7 @@ const Packages = () => {
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => refetch()}
|
||||
disabled={isFetching}
|
||||
className="btn-outline flex items-center gap-2"
|
||||
@@ -524,6 +527,7 @@ const Packages = () => {
|
||||
{/* Columns Button */}
|
||||
<div className="flex items-center">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowColumnSettings(true)}
|
||||
className="flex items-center gap-2 px-3 py-2 text-sm text-secondary-700 dark:text-secondary-300 bg-white dark:bg-secondary-700 border border-secondary-300 dark:border-secondary-600 rounded-md hover:bg-secondary-50 dark:hover:bg-secondary-600 transition-colors"
|
||||
>
|
||||
@@ -560,6 +564,7 @@ const Packages = () => {
|
||||
className="px-4 py-2 text-center text-xs font-medium text-secondary-500 dark:text-secondary-300 uppercase tracking-wider"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleSort(column.id)}
|
||||
className="flex items-center gap-1 hover:text-secondary-700 dark:hover:text-secondary-200 transition-colors"
|
||||
>
|
||||
@@ -644,6 +649,7 @@ const ColumnSettingsModal = ({
|
||||
Customize Columns
|
||||
</h3>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className="text-secondary-400 hover:text-secondary-600 dark:text-secondary-500 dark:hover:text-secondary-300"
|
||||
>
|
||||
@@ -672,6 +678,7 @@ const ColumnSettingsModal = ({
|
||||
</span>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onToggleVisibility(column.id)}
|
||||
className={`p-1 rounded ${
|
||||
column.visible
|
||||
@@ -691,12 +698,14 @@ const ColumnSettingsModal = ({
|
||||
|
||||
<div className="flex justify-between mt-6">
|
||||
<button
|
||||
type="button"
|
||||
onClick={onReset}
|
||||
className="px-4 py-2 text-sm font-medium text-secondary-700 dark:text-secondary-200 bg-white dark:bg-secondary-700 border border-secondary-300 dark:border-secondary-600 rounded-md hover:bg-secondary-50 dark:hover:bg-secondary-600"
|
||||
>
|
||||
Reset to Default
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className="px-4 py-2 text-sm font-medium text-white bg-primary-600 rounded-md hover:bg-primary-700"
|
||||
>
|
||||
|
||||
@@ -108,6 +108,7 @@ const Permissions = () => {
|
||||
<div className="flex justify-end items-center">
|
||||
<div className="flex space-x-3">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => refreshPermissions()}
|
||||
className="inline-flex items-center px-4 py-2 border border-secondary-300 text-sm font-medium rounded-md text-secondary-700 bg-white hover:bg-secondary-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500"
|
||||
>
|
||||
@@ -115,6 +116,7 @@ const Permissions = () => {
|
||||
Refresh Permissions
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowAddModal(true)}
|
||||
className="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500"
|
||||
>
|
||||
@@ -265,6 +267,7 @@ const RolePermissionsCard = ({
|
||||
{isEditing ? (
|
||||
<>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleSave}
|
||||
className="inline-flex items-center px-3 py-1 border border-transparent text-sm font-medium rounded-md text-white bg-green-600 hover:bg-green-700"
|
||||
>
|
||||
@@ -272,6 +275,7 @@ const RolePermissionsCard = ({
|
||||
Save
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onCancel}
|
||||
className="inline-flex items-center px-3 py-1 border border-secondary-300 dark:border-secondary-600 text-sm font-medium rounded-md text-secondary-700 dark:text-secondary-200 bg-white dark:bg-secondary-700 hover:bg-secondary-50 dark:hover:bg-secondary-600"
|
||||
>
|
||||
@@ -282,6 +286,7 @@ const RolePermissionsCard = ({
|
||||
) : (
|
||||
<>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onEdit}
|
||||
disabled={isBuiltInRole}
|
||||
className="inline-flex items-center px-3 py-1 border border-transparent text-sm font-medium rounded-md text-white bg-primary-600 hover:bg-primary-700 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
@@ -291,6 +296,7 @@ const RolePermissionsCard = ({
|
||||
</button>
|
||||
{!isBuiltInRole && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onDelete(role.role)}
|
||||
className="inline-flex items-center px-3 py-1 border border-transparent text-sm font-medium rounded-md text-white bg-red-600 hover:bg-red-700"
|
||||
>
|
||||
|
||||
@@ -192,6 +192,7 @@ const Profile = () => {
|
||||
const Icon = tab.icon;
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
key={tab.id}
|
||||
onClick={() => setActiveTab(tab.id)}
|
||||
className={`py-4 px-1 border-b-2 font-medium text-sm flex items-center ${
|
||||
@@ -505,6 +506,7 @@ const Profile = () => {
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={toggleTheme}
|
||||
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2 ${
|
||||
isDark ? "bg-primary-600" : "bg-secondary-300"
|
||||
@@ -797,6 +799,7 @@ const TfaTab = () => {
|
||||
<div>
|
||||
{tfaStatus?.enabled ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setSetupStep("disable")}
|
||||
className="btn-outline text-danger-600 border-danger-300 hover:bg-danger-50"
|
||||
>
|
||||
@@ -805,6 +808,7 @@ const TfaTab = () => {
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleSetup}
|
||||
disabled={setupMutation.isPending}
|
||||
className="btn-primary"
|
||||
@@ -827,6 +831,7 @@ const TfaTab = () => {
|
||||
authenticator device.
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleRegenerateBackupCodes}
|
||||
disabled={regenerateBackupCodesMutation.isPending}
|
||||
className="btn-outline"
|
||||
@@ -871,6 +876,7 @@ const TfaTab = () => {
|
||||
{setupMutation.data.manualEntryKey}
|
||||
</code>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
copyToClipboard(setupMutation.data.manualEntryKey)
|
||||
}
|
||||
@@ -884,6 +890,7 @@ const TfaTab = () => {
|
||||
|
||||
<div className="text-center">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setSetupStep("verify")}
|
||||
className="btn-primary"
|
||||
>
|
||||
@@ -979,11 +986,12 @@ const TfaTab = () => {
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex space-x-3">
|
||||
<button onClick={downloadBackupCodes} className="btn-outline">
|
||||
<button type="button" onClick={downloadBackupCodes} className="btn-outline">
|
||||
<Download className="h-4 w-4 mr-2" />
|
||||
Download Codes
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
setSetupStep("status");
|
||||
queryClient.invalidateQueries(["tfaStatus"]);
|
||||
|
||||
@@ -238,6 +238,7 @@ const Repositories = () => {
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => refetch()}
|
||||
disabled={isFetching}
|
||||
className="btn-outline flex items-center gap-2"
|
||||
@@ -363,6 +364,7 @@ const Repositories = () => {
|
||||
{/* Columns Button */}
|
||||
<div className="flex items-center">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowColumnSettings(true)}
|
||||
className="flex items-center gap-2 px-3 py-2 text-sm text-secondary-700 dark:text-secondary-300 bg-white dark:bg-secondary-700 border border-secondary-300 dark:border-secondary-600 rounded-md hover:bg-secondary-50 dark:hover:bg-secondary-600 transition-colors"
|
||||
>
|
||||
@@ -399,6 +401,7 @@ const Repositories = () => {
|
||||
className="px-4 py-2 text-center text-xs font-medium text-secondary-500 dark:text-secondary-300 uppercase tracking-wider"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleSort(column.id)}
|
||||
className="flex items-center gap-1 hover:text-secondary-700 dark:hover:text-secondary-200 transition-colors"
|
||||
>
|
||||
@@ -567,6 +570,7 @@ const ColumnSettingsModal = ({
|
||||
Column Settings
|
||||
</h3>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className="text-secondary-400 hover:text-secondary-600 dark:text-secondary-500 dark:hover:text-secondary-300"
|
||||
>
|
||||
@@ -591,6 +595,7 @@ const ColumnSettingsModal = ({
|
||||
</span>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onToggleVisibility(column.id)}
|
||||
className={`w-4 h-4 rounded border-2 flex items-center justify-center ${
|
||||
column.visible
|
||||
@@ -606,12 +611,14 @@ const ColumnSettingsModal = ({
|
||||
|
||||
<div className="flex justify-between mt-6">
|
||||
<button
|
||||
type="button"
|
||||
onClick={onReset}
|
||||
className="px-4 py-2 text-sm text-secondary-600 dark:text-secondary-400 hover:text-secondary-800 dark:hover:text-secondary-200"
|
||||
>
|
||||
Reset to Default
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className="px-4 py-2 bg-primary-600 text-white text-sm rounded-md hover:bg-primary-700 transition-colors"
|
||||
>
|
||||
|
||||
@@ -161,6 +161,7 @@ const RepositoryDetail = () => {
|
||||
{editMode ? (
|
||||
<>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleCancel}
|
||||
className="btn-outline"
|
||||
disabled={updateRepositoryMutation.isPending}
|
||||
@@ -168,6 +169,7 @@ const RepositoryDetail = () => {
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleSave}
|
||||
className="btn-primary"
|
||||
disabled={updateRepositoryMutation.isPending}
|
||||
@@ -178,7 +180,7 @@ const RepositoryDetail = () => {
|
||||
</button>
|
||||
</>
|
||||
) : (
|
||||
<button onClick={handleEdit} className="btn-primary">
|
||||
<button type="button" onClick={handleEdit} className="btn-primary">
|
||||
Edit Repository
|
||||
</button>
|
||||
)}
|
||||
|
||||
@@ -431,6 +431,7 @@ const Settings = () => {
|
||||
const Icon = tab.icon;
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
key={tab.id}
|
||||
onClick={() => setActiveTab(tab.id)}
|
||||
className={`py-4 px-1 border-b-2 font-medium text-sm flex items-center gap-2 ${
|
||||
@@ -792,6 +793,7 @@ const Settings = () => {
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowAgentVersionModal(true)}
|
||||
className="btn-primary flex items-center gap-2"
|
||||
>
|
||||
@@ -888,6 +890,7 @@ const Settings = () => {
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
const downloadUrl = `/api/v1/hosts/agent/download?version=${version.version}`;
|
||||
window.open(downloadUrl, "_blank");
|
||||
@@ -898,6 +901,7 @@ const Settings = () => {
|
||||
Download
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
setCurrentAgentVersionMutation.mutate(version.id)
|
||||
}
|
||||
@@ -911,6 +915,7 @@ const Settings = () => {
|
||||
Set Current
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
setDefaultAgentVersionMutation.mutate(version.id)
|
||||
}
|
||||
@@ -924,6 +929,7 @@ const Settings = () => {
|
||||
Set Default
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
deleteAgentVersionMutation.mutate(version.id)
|
||||
}
|
||||
@@ -1208,6 +1214,7 @@ const Settings = () => {
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<button
|
||||
type="button"
|
||||
onClick={checkForUpdates}
|
||||
disabled={versionInfo.checking}
|
||||
className="btn-primary flex items-center gap-2"
|
||||
@@ -1360,6 +1367,7 @@ const AgentVersionModal = ({ isOpen, onClose, onSubmit, isLoading }) => {
|
||||
Add Agent Version
|
||||
</h3>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className="text-secondary-400 hover:text-secondary-600 dark:text-secondary-500 dark:hover:text-secondary-300"
|
||||
>
|
||||
|
||||
@@ -121,6 +121,7 @@ const Users = () => {
|
||||
{/* Header */}
|
||||
<div className="flex justify-end items-center">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowAddModal(true)}
|
||||
className="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500"
|
||||
>
|
||||
@@ -193,6 +194,7 @@ const Users = () => {
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleEditUser(user)}
|
||||
className="text-secondary-400 hover:text-secondary-600 dark:text-secondary-500 dark:hover:text-secondary-300"
|
||||
title="Edit user"
|
||||
@@ -200,6 +202,7 @@ const Users = () => {
|
||||
<Edit className="h-4 w-4" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleResetPassword(user)}
|
||||
className="text-blue-400 hover:text-blue-600 dark:text-blue-500 dark:hover:text-blue-300 disabled:text-gray-300 disabled:cursor-not-allowed"
|
||||
title={
|
||||
@@ -212,6 +215,7 @@ const Users = () => {
|
||||
<Key className="h-4 w-4" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleDeleteUser(user.id, user.username)}
|
||||
className="text-danger-400 hover:text-danger-600 dark:text-danger-500 dark:hover:text-danger-400 disabled:text-gray-300 disabled:cursor-not-allowed"
|
||||
title={
|
||||
|
||||
Reference in New Issue
Block a user