- nodes: port node-type (traditional/agent) picker back from web-src into the embedded frontend; backend annotates NodeView.nodeType from agent_nodes bindings; fix agent-node update path (skip reachability probe and apiToken requirement for agent-managed nodes); restore i18n keys in all 13 locales; install command now uses the Gitea mirror - jobs: expire agent-bound nodes whose agent_nodes.last_seen is older than max(3x heartbeat interval, 120s) = 180s; last_seen=0 (never registered) is left untouched; transitions reuse UpdateHeartbeat + node event broadcast - config: GetBaseVersion honors ldflags-injected buildVersion; release builds inject 3.7.0-agent.1 so the panel no longer reports a phantom update against the Gitea release tag - logger/server: remove the three log viewers (panel/xray/amneziawg), their API endpoints and the 10240-entry in-memory log buffer; file logging via lumberjack unchanged; tests assert via a new optional logger hook instead of the removed buffer - server: remove system history and xray metrics modules end to end (endpoints, sampling appends in RefreshStatus, per-minute persist cron, gob snapshot/restore, XrayMetricsService); realtime status and per-node history are untouched - settings: subPort may be 0/unset - subscription links are generated without a port while the subscription service keeps binding the default 2096; the settings form declares the cleared state via onNumber's new onClear option instead of snapping back to 1
91 lines
2.3 KiB
TypeScript
91 lines
2.3 KiB
TypeScript
import type { ReactNode } from 'react';
|
|
import { useTranslation } from 'react-i18next';
|
|
import { Button, Tag, Tooltip } from 'antd';
|
|
import { CloudDownloadOutlined, CloudServerOutlined, ControlOutlined } from '@ant-design/icons';
|
|
|
|
import { formatPanelVersion } from '@/lib/panel-version';
|
|
|
|
interface OverviewActionBarProps {
|
|
isMobile: boolean;
|
|
panelVersion: string;
|
|
latestVersion: string;
|
|
updateAvailable: boolean;
|
|
onOpenConfig: () => void;
|
|
onOpenBackup: () => void;
|
|
onOpenPanelUpdate: () => void;
|
|
}
|
|
|
|
interface BarAction {
|
|
key: string;
|
|
icon: ReactNode;
|
|
text: string;
|
|
onClick: () => void;
|
|
primary?: boolean;
|
|
}
|
|
|
|
export default function OverviewActionBar({
|
|
isMobile,
|
|
panelVersion,
|
|
latestVersion,
|
|
updateAvailable,
|
|
onOpenConfig,
|
|
onOpenBackup,
|
|
onOpenPanelUpdate,
|
|
}: OverviewActionBarProps) {
|
|
const { t } = useTranslation();
|
|
const size = isMobile ? ('small' as const) : ('middle' as const);
|
|
|
|
const actions: BarAction[] = [
|
|
{
|
|
key: 'config',
|
|
icon: <ControlOutlined />,
|
|
text: t('pages.index.config'),
|
|
onClick: onOpenConfig,
|
|
},
|
|
{
|
|
key: 'backup',
|
|
icon: <CloudServerOutlined />,
|
|
text: t('pages.index.backupTitle'),
|
|
onClick: onOpenBackup,
|
|
},
|
|
];
|
|
|
|
return (
|
|
<div className="ov-bar">
|
|
{updateAvailable ? (
|
|
<Tag
|
|
className="ov-update-tag"
|
|
color="warning"
|
|
icon={<CloudDownloadOutlined />}
|
|
onClick={onOpenPanelUpdate}
|
|
>
|
|
{`${t('update')} ${formatPanelVersion(latestVersion)}`}
|
|
</Tag>
|
|
) : (
|
|
<Tooltip title={t('pages.index.updatePanel')}>
|
|
<button type="button" className="ov-panel-version ov-mono" onClick={onOpenPanelUpdate}>
|
|
{formatPanelVersion(panelVersion)}
|
|
</button>
|
|
</Tooltip>
|
|
)}
|
|
|
|
<div className="ov-bar-actions">
|
|
{actions.map((action) => (
|
|
<Button
|
|
key={action.key}
|
|
type={action.primary ? undefined : 'text'}
|
|
color={action.primary ? 'primary' : undefined}
|
|
variant={action.primary ? 'outlined' : undefined}
|
|
size={size}
|
|
icon={action.icon}
|
|
aria-label={action.text}
|
|
onClick={action.onClick}
|
|
>
|
|
{isMobile ? undefined : action.text}
|
|
</Button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|