Files
l-ui/frontend/src/pages/index/OverviewActionBar.tsx
T
Muse f887f47bb9 P7: restore agent node type, agent heartbeat expiry, build-version injection, remove log/history/xray-metrics modules, optional sub port
- 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
2026-10-21 06:44:00 +00:00

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>
);
}