mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-10 18:45:53 +00:00
Extract Proxmox settings panel owners
This commit is contained in:
@@ -40,22 +40,25 @@ management, and fleet control surfaces.
|
||||
16. `frontend-modern/src/components/Settings/InfrastructureWorkspace.tsx`
|
||||
17. `frontend-modern/src/components/Settings/infrastructureWorkspaceModel.ts`
|
||||
18. `frontend-modern/src/components/Settings/ProxmoxSettingsPanel.tsx`
|
||||
19. `frontend-modern/src/components/Settings/ProxmoxDirectConnectionsCard.tsx`
|
||||
20. `frontend-modern/src/components/Settings/ProxmoxDiscoveryResultsCard.tsx`
|
||||
21. `frontend-modern/src/components/Settings/ProxmoxDeleteNodeDialog.tsx`
|
||||
22. `frontend-modern/src/components/Settings/ConfiguredNodeTables.tsx`
|
||||
23. `frontend-modern/src/components/Settings/SettingsSectionNav.tsx`
|
||||
24. `frontend-modern/src/components/Settings/useInfrastructureOperationsState.tsx`
|
||||
25. `frontend-modern/src/components/Settings/useInfrastructureSettingsState.ts`
|
||||
26. `frontend-modern/src/components/Settings/UnifiedAgents.tsx`
|
||||
27. `frontend-modern/src/components/Settings/NodeModal.tsx`
|
||||
28. `frontend-modern/src/components/Settings/nodeModalModel.ts`
|
||||
29. `frontend-modern/src/components/Settings/useNodeModalState.ts`
|
||||
30. `frontend-modern/src/components/SetupWizard/SetupCompletionPanel.tsx`
|
||||
31. `frontend-modern/src/components/Infrastructure/deploy/ResultsStep.tsx`
|
||||
32. `frontend-modern/src/utils/agentProfilesPresentation.ts`
|
||||
33. `frontend-modern/src/utils/agentInstallCommand.ts`
|
||||
34. `frontend-modern/src/api/nodes.ts`
|
||||
19. `frontend-modern/src/components/Settings/ProxmoxConfiguredNodesTable.tsx`
|
||||
20. `frontend-modern/src/components/Settings/ProxmoxDirectConnectionsCard.tsx`
|
||||
21. `frontend-modern/src/components/Settings/ProxmoxDiscoveryResultsCard.tsx`
|
||||
22. `frontend-modern/src/components/Settings/ProxmoxDeleteNodeDialog.tsx`
|
||||
23. `frontend-modern/src/components/Settings/ProxmoxNodeModalStack.tsx`
|
||||
24. `frontend-modern/src/components/Settings/ConfiguredNodeTables.tsx`
|
||||
25. `frontend-modern/src/components/Settings/SettingsSectionNav.tsx`
|
||||
26. `frontend-modern/src/components/Settings/useInfrastructureOperationsState.tsx`
|
||||
27. `frontend-modern/src/components/Settings/useInfrastructureSettingsState.ts`
|
||||
28. `frontend-modern/src/components/Settings/useProxmoxSettingsPanelState.ts`
|
||||
29. `frontend-modern/src/components/Settings/UnifiedAgents.tsx`
|
||||
30. `frontend-modern/src/components/Settings/NodeModal.tsx`
|
||||
31. `frontend-modern/src/components/Settings/nodeModalModel.ts`
|
||||
32. `frontend-modern/src/components/Settings/useNodeModalState.ts`
|
||||
33. `frontend-modern/src/components/SetupWizard/SetupCompletionPanel.tsx`
|
||||
34. `frontend-modern/src/components/Infrastructure/deploy/ResultsStep.tsx`
|
||||
35. `frontend-modern/src/utils/agentProfilesPresentation.ts`
|
||||
36. `frontend-modern/src/utils/agentInstallCommand.ts`
|
||||
37. `frontend-modern/src/api/nodes.ts`
|
||||
|
||||
## Shared Boundaries
|
||||
|
||||
@@ -82,7 +85,7 @@ management, and fleet control surfaces.
|
||||
3. Add or change runtime-side Unified Agent startup, first-report assembly, and enroll/runtime continuity through `internal/hostagent/`.
|
||||
4. Keep legacy Unified Agent compatibility names explicitly secondary when touching shared `internal/api/` runtime helpers: the legacy host-route family and `host-agent:*` scope names may remain as ingress or migration aliases, but they must not retake primary ownership in router state, live runtime scope checks, handler commentary, or operator-facing guidance.
|
||||
5. Add or change installer flags, persisted service arguments, or upgrade-safe re-entry behavior through `scripts/install.sh` and `scripts/install.ps1`.
|
||||
6. Add or change profile management, the extracted agent profiles runtime owner, the pure unified-agent inventory/install model, the direct Proxmox workspace shell, route model, reporting summary owner, and section owners, shared frontend install-command assembly, Proxmox setup/install API transport, setup-completion install handoff transport, deploy-fallback manual install transport, and fleet-control presentation through `frontend-modern/src/api/agentProfiles.ts`, `frontend-modern/src/api/nodes.ts`, `frontend-modern/src/components/Settings/AgentProfilesPanel.tsx`, `frontend-modern/src/components/Settings/useAgentProfilesPanelState.ts`, `frontend-modern/src/components/Settings/InfrastructureOperationsController.tsx`, `frontend-modern/src/components/Settings/infrastructureOperationsModel.tsx`, `frontend-modern/src/components/Settings/InfrastructureInstallPanel.tsx`, `frontend-modern/src/components/Settings/InfrastructureReportingPanel.tsx`, `frontend-modern/src/components/Settings/InfrastructureDirectConnectionsSummaryCard.tsx`, `frontend-modern/src/components/Settings/InfrastructureWorkspace.tsx`, `frontend-modern/src/components/Settings/infrastructureWorkspaceModel.ts`, `frontend-modern/src/components/Settings/ProxmoxSettingsPanel.tsx`, `frontend-modern/src/components/Settings/ProxmoxDirectConnectionsCard.tsx`, `frontend-modern/src/components/Settings/ProxmoxDiscoveryResultsCard.tsx`, `frontend-modern/src/components/Settings/ProxmoxDeleteNodeDialog.tsx`, `frontend-modern/src/components/Settings/ConfiguredNodeTables.tsx`, `frontend-modern/src/components/Settings/SettingsSectionNav.tsx`, `frontend-modern/src/components/Settings/useInfrastructureOperationsState.tsx`, `frontend-modern/src/components/Settings/useInfrastructureSettingsState.ts`, `frontend-modern/src/components/Settings/NodeModal.tsx`, `frontend-modern/src/components/Settings/nodeModalModel.ts`, `frontend-modern/src/components/Settings/useNodeModalState.ts`, `frontend-modern/src/components/SetupWizard/SetupCompletionPanel.tsx`, `frontend-modern/src/components/Infrastructure/deploy/ResultsStep.tsx`, and `frontend-modern/src/utils/agentInstallCommand.ts`.
|
||||
6. Add or change profile management, the extracted agent profiles runtime owner, the pure unified-agent inventory/install model, the direct Proxmox workspace shell, route model, reporting summary owner, local panel-state owner, and section owners, shared frontend install-command assembly, Proxmox setup/install API transport, setup-completion install handoff transport, deploy-fallback manual install transport, and fleet-control presentation through `frontend-modern/src/api/agentProfiles.ts`, `frontend-modern/src/api/nodes.ts`, `frontend-modern/src/components/Settings/AgentProfilesPanel.tsx`, `frontend-modern/src/components/Settings/useAgentProfilesPanelState.ts`, `frontend-modern/src/components/Settings/InfrastructureOperationsController.tsx`, `frontend-modern/src/components/Settings/infrastructureOperationsModel.tsx`, `frontend-modern/src/components/Settings/InfrastructureInstallPanel.tsx`, `frontend-modern/src/components/Settings/InfrastructureReportingPanel.tsx`, `frontend-modern/src/components/Settings/InfrastructureDirectConnectionsSummaryCard.tsx`, `frontend-modern/src/components/Settings/InfrastructureWorkspace.tsx`, `frontend-modern/src/components/Settings/infrastructureWorkspaceModel.ts`, `frontend-modern/src/components/Settings/ProxmoxSettingsPanel.tsx`, `frontend-modern/src/components/Settings/ProxmoxConfiguredNodesTable.tsx`, `frontend-modern/src/components/Settings/ProxmoxDirectConnectionsCard.tsx`, `frontend-modern/src/components/Settings/ProxmoxDiscoveryResultsCard.tsx`, `frontend-modern/src/components/Settings/ProxmoxDeleteNodeDialog.tsx`, `frontend-modern/src/components/Settings/ProxmoxNodeModalStack.tsx`, `frontend-modern/src/components/Settings/ConfiguredNodeTables.tsx`, `frontend-modern/src/components/Settings/SettingsSectionNav.tsx`, `frontend-modern/src/components/Settings/useInfrastructureOperationsState.tsx`, `frontend-modern/src/components/Settings/useInfrastructureSettingsState.ts`, `frontend-modern/src/components/Settings/useProxmoxSettingsPanelState.ts`, `frontend-modern/src/components/Settings/NodeModal.tsx`, `frontend-modern/src/components/Settings/nodeModalModel.ts`, `frontend-modern/src/components/Settings/useNodeModalState.ts`, `frontend-modern/src/components/SetupWizard/SetupCompletionPanel.tsx`, `frontend-modern/src/components/Infrastructure/deploy/ResultsStep.tsx`, and `frontend-modern/src/utils/agentInstallCommand.ts`.
|
||||
|
||||
## Forbidden Paths
|
||||
|
||||
@@ -154,10 +157,12 @@ lifecycle boundary: `InfrastructureWorkspace.tsx`,
|
||||
`infrastructureWorkspaceModel.ts`,
|
||||
`InfrastructureInstallPanel.tsx`, `InfrastructureReportingPanel.tsx`,
|
||||
`InfrastructureDirectConnectionsSummaryCard.tsx`,
|
||||
`ProxmoxSettingsPanel.tsx`, `ProxmoxDirectConnectionsCard.tsx`,
|
||||
`ProxmoxDiscoveryResultsCard.tsx`, `ProxmoxDeleteNodeDialog.tsx`,
|
||||
`ConfiguredNodeTables.tsx`, `SettingsSectionNav.tsx`, and
|
||||
`useInfrastructureSettingsState.ts` own the fallback install/direct/reporting
|
||||
`ProxmoxSettingsPanel.tsx`, `ProxmoxConfiguredNodesTable.tsx`,
|
||||
`ProxmoxDirectConnectionsCard.tsx`, `ProxmoxDiscoveryResultsCard.tsx`,
|
||||
`ProxmoxDeleteNodeDialog.tsx`, `ProxmoxNodeModalStack.tsx`,
|
||||
`ConfiguredNodeTables.tsx`, `SettingsSectionNav.tsx`,
|
||||
`useInfrastructureSettingsState.ts`, and
|
||||
`useProxmoxSettingsPanelState.ts` own the fallback install/direct/reporting
|
||||
operator flow instead of leaving those panels ungoverned beside the canonical
|
||||
unified-agent install path.
|
||||
That canonical /api/auto-register behavior now also includes hostname/IP continuity:
|
||||
|
||||
@@ -378,9 +378,11 @@
|
||||
"frontend-modern/src/components/Settings/infrastructureWorkspaceModel.ts",
|
||||
"frontend-modern/src/components/Settings/NodeModal.tsx",
|
||||
"frontend-modern/src/components/Settings/nodeModalModel.ts",
|
||||
"frontend-modern/src/components/Settings/ProxmoxConfiguredNodesTable.tsx",
|
||||
"frontend-modern/src/components/Settings/ProxmoxDeleteNodeDialog.tsx",
|
||||
"frontend-modern/src/components/Settings/ProxmoxDirectConnectionsCard.tsx",
|
||||
"frontend-modern/src/components/Settings/ProxmoxDiscoveryResultsCard.tsx",
|
||||
"frontend-modern/src/components/Settings/ProxmoxNodeModalStack.tsx",
|
||||
"frontend-modern/src/components/Settings/ProxmoxSettingsPanel.tsx",
|
||||
"frontend-modern/src/components/Settings/SettingsSectionNav.tsx",
|
||||
"frontend-modern/src/components/Settings/UnifiedAgents.tsx",
|
||||
@@ -388,6 +390,7 @@
|
||||
"frontend-modern/src/components/Settings/useInfrastructureOperationsState.tsx",
|
||||
"frontend-modern/src/components/Settings/useInfrastructureSettingsState.ts",
|
||||
"frontend-modern/src/components/Settings/useNodeModalState.ts",
|
||||
"frontend-modern/src/components/Settings/useProxmoxSettingsPanelState.ts",
|
||||
"frontend-modern/src/components/SetupWizard/SetupCompletionPanel.tsx",
|
||||
"frontend-modern/src/utils/agentInstallCommand.ts",
|
||||
"frontend-modern/src/utils/agentProfilesPresentation.ts",
|
||||
@@ -611,12 +614,15 @@
|
||||
"frontend-modern/src/components/Settings/InfrastructureReportingPanel.tsx",
|
||||
"frontend-modern/src/components/Settings/InfrastructureWorkspace.tsx",
|
||||
"frontend-modern/src/components/Settings/infrastructureWorkspaceModel.ts",
|
||||
"frontend-modern/src/components/Settings/ProxmoxConfiguredNodesTable.tsx",
|
||||
"frontend-modern/src/components/Settings/ProxmoxDeleteNodeDialog.tsx",
|
||||
"frontend-modern/src/components/Settings/ProxmoxDirectConnectionsCard.tsx",
|
||||
"frontend-modern/src/components/Settings/ProxmoxDiscoveryResultsCard.tsx",
|
||||
"frontend-modern/src/components/Settings/ProxmoxNodeModalStack.tsx",
|
||||
"frontend-modern/src/components/Settings/ProxmoxSettingsPanel.tsx",
|
||||
"frontend-modern/src/components/Settings/SettingsSectionNav.tsx",
|
||||
"frontend-modern/src/components/Settings/useInfrastructureSettingsState.ts"
|
||||
"frontend-modern/src/components/Settings/useInfrastructureSettingsState.ts",
|
||||
"frontend-modern/src/components/Settings/useProxmoxSettingsPanelState.ts"
|
||||
],
|
||||
"allow_same_subsystem_tests": false,
|
||||
"test_prefixes": [],
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
import type { Component } from 'solid-js';
|
||||
import type { Resource } from '@/types/resource';
|
||||
import type { PBSInstance, PMGInstance } from '@/types/api';
|
||||
import type { NodeConfigWithStatus } from '@/types/nodes';
|
||||
import { PveNodesTable, PbsNodesTable, PmgNodesTable } from './ConfiguredNodeTables';
|
||||
import type { NodeType } from './useInfrastructureSettingsState';
|
||||
|
||||
interface ProxmoxConfiguredNodesTableProps {
|
||||
activeAgent: NodeType;
|
||||
pveNodes: NodeConfigWithStatus[];
|
||||
pbsNodes: NodeConfigWithStatus[];
|
||||
pmgNodes: NodeConfigWithStatus[];
|
||||
agentStateResources: Resource[];
|
||||
pbsInstances: PBSInstance[];
|
||||
pmgInstances: PMGInstance[];
|
||||
temperatureMonitoringEnabled: boolean;
|
||||
onTestConnection: (nodeId: string) => void;
|
||||
onEditNode: (type: NodeType, node: NodeConfigWithStatus) => void;
|
||||
onDeleteNode: (node: NodeConfigWithStatus) => void;
|
||||
onRefreshClusterNodes: (nodeId: string) => Promise<void>;
|
||||
}
|
||||
|
||||
export const ProxmoxConfiguredNodesTable: Component<ProxmoxConfiguredNodesTableProps> = (
|
||||
props,
|
||||
) => {
|
||||
switch (props.activeAgent) {
|
||||
case 'pve':
|
||||
return (
|
||||
<PveNodesTable
|
||||
nodes={props.pveNodes}
|
||||
stateNodes={props.agentStateResources}
|
||||
globalTemperatureMonitoringEnabled={props.temperatureMonitoringEnabled}
|
||||
onTestConnection={props.onTestConnection}
|
||||
onEdit={(node) => props.onEditNode('pve', node)}
|
||||
onDelete={props.onDeleteNode}
|
||||
onRefreshCluster={props.onRefreshClusterNodes}
|
||||
/>
|
||||
);
|
||||
case 'pbs':
|
||||
return (
|
||||
<PbsNodesTable
|
||||
nodes={props.pbsNodes}
|
||||
statePbs={props.pbsInstances}
|
||||
globalTemperatureMonitoringEnabled={props.temperatureMonitoringEnabled}
|
||||
onTestConnection={props.onTestConnection}
|
||||
onEdit={(node) => props.onEditNode('pbs', node)}
|
||||
onDelete={props.onDeleteNode}
|
||||
/>
|
||||
);
|
||||
case 'pmg':
|
||||
return (
|
||||
<PmgNodesTable
|
||||
nodes={props.pmgNodes}
|
||||
statePmg={props.pmgInstances}
|
||||
globalTemperatureMonitoringEnabled={props.temperatureMonitoringEnabled}
|
||||
onTestConnection={props.onTestConnection}
|
||||
onEdit={(node) => props.onEditNode('pmg', node)}
|
||||
onDelete={props.onDeleteNode}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default ProxmoxConfiguredNodesTable;
|
||||
@@ -0,0 +1,57 @@
|
||||
import { Show, type Component } from 'solid-js';
|
||||
import type { NodeConfig, NodeConfigWithStatus } from '@/types/nodes';
|
||||
import type { SecurityStatus as SecurityStatusInfo } from '@/types/config';
|
||||
import { NodeModal } from './NodeModal';
|
||||
import type { NodeType } from './useInfrastructureSettingsState';
|
||||
|
||||
interface ProxmoxNodeModalStackProps {
|
||||
modalResetKey: number;
|
||||
prefillNode: Partial<NodeConfig> | null;
|
||||
editingNodeType: NodeType | null;
|
||||
editingNode: () => NodeConfigWithStatus | null;
|
||||
isNodeModalVisible: (type: NodeType) => boolean;
|
||||
securityStatus: SecurityStatusInfo | null;
|
||||
resolveTemperatureMonitoringEnabled: (node?: NodeConfigWithStatus | null) => boolean;
|
||||
temperatureMonitoringLocked: boolean;
|
||||
savingTemperatureSetting: boolean;
|
||||
handleNodeTemperatureMonitoringChange: (nodeId: string, enabled: boolean | null) => Promise<void>;
|
||||
handleTemperatureMonitoringChange: (enabled: boolean) => Promise<void>;
|
||||
saveNode: (nodeData: Partial<NodeConfig>) => Promise<void>;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
const PROXMOX_NODE_TYPES: readonly NodeType[] = ['pve', 'pbs', 'pmg'];
|
||||
|
||||
export const ProxmoxNodeModalStack: Component<ProxmoxNodeModalStackProps> = (props) => {
|
||||
return (
|
||||
<>
|
||||
{PROXMOX_NODE_TYPES.map((type) => (
|
||||
<Show when={props.isNodeModalVisible(type)}>
|
||||
<NodeModal
|
||||
isOpen={true}
|
||||
resetKey={props.modalResetKey}
|
||||
onClose={props.onClose}
|
||||
nodeType={type}
|
||||
editingNode={props.editingNodeType === type ? props.editingNode() ?? undefined : undefined}
|
||||
prefillNode={props.prefillNode?.type === type ? props.prefillNode ?? undefined : undefined}
|
||||
securityStatus={props.securityStatus ?? undefined}
|
||||
temperatureMonitoringEnabled={props.resolveTemperatureMonitoringEnabled(
|
||||
props.editingNodeType === type ? props.editingNode() : null,
|
||||
)}
|
||||
temperatureMonitoringLocked={props.temperatureMonitoringLocked}
|
||||
savingTemperatureSetting={props.savingTemperatureSetting}
|
||||
onToggleTemperatureMonitoring={
|
||||
props.editingNode()?.id
|
||||
? (enabled: boolean) =>
|
||||
props.handleNodeTemperatureMonitoringChange(props.editingNode()!.id, enabled)
|
||||
: props.handleTemperatureMonitoringChange
|
||||
}
|
||||
onSave={props.saveNode}
|
||||
/>
|
||||
</Show>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProxmoxNodeModalStack;
|
||||
@@ -1,22 +1,18 @@
|
||||
import { Component, Accessor, Setter, Show, createMemo, createSignal } from 'solid-js';
|
||||
import { Component, Accessor, Setter, Show } from 'solid-js';
|
||||
import { useNavigate } from '@solidjs/router';
|
||||
import type { Resource } from '@/types/resource';
|
||||
import type { PBSInstance, PMGInstance } from '@/types/api';
|
||||
import type { NodeConfig, NodeConfigWithStatus } from '@/types/nodes';
|
||||
import type { SecurityStatus as SecurityStatusInfo } from '@/types/config';
|
||||
import { notificationStore } from '@/stores/notifications';
|
||||
import { CalloutCard } from '@/components/shared/CalloutCard';
|
||||
import type { ToggleChangeEvent } from '@/components/shared/Toggle';
|
||||
import { NodeModal } from './NodeModal';
|
||||
import { PveNodesTable, PbsNodesTable, PmgNodesTable } from './ConfiguredNodeTables';
|
||||
import { ProxmoxConfiguredNodesTable } from './ProxmoxConfiguredNodesTable';
|
||||
import { ProxmoxDeleteNodeDialog } from './ProxmoxDeleteNodeDialog';
|
||||
import { ProxmoxDirectConnectionsCard } from './ProxmoxDirectConnectionsCard';
|
||||
import { ProxmoxDiscoveryResultsCard } from './ProxmoxDiscoveryResultsCard';
|
||||
import { ProxmoxNodeModalStack } from './ProxmoxNodeModalStack';
|
||||
import { SettingsSectionNav } from './SettingsSectionNav';
|
||||
import {
|
||||
buildProxmoxDiscoveryPrefillNode,
|
||||
getProxmoxVariantPresentation,
|
||||
} from '@/utils/proxmoxSettingsPresentation';
|
||||
import { useProxmoxSettingsPanelState } from './useProxmoxSettingsPanelState';
|
||||
import type {
|
||||
DiscoveredServer,
|
||||
DiscoveryScanStatus,
|
||||
@@ -75,145 +71,16 @@ export interface ProxmoxSettingsPanelProps {
|
||||
|
||||
export const ProxmoxSettingsPanel: Component<ProxmoxSettingsPanelProps> = (props) => {
|
||||
const navigate = useNavigate();
|
||||
const [prefillNode, setPrefillNode] = createSignal<Partial<NodeConfig> | null>(null);
|
||||
|
||||
const activeAgent = () => props.selectedAgent();
|
||||
const activeConfig = createMemo(() => getProxmoxVariantPresentation(activeAgent()));
|
||||
const activeDiscoveredNodes = createMemo(() =>
|
||||
props.discoveredNodes().filter((node) => node.type === activeAgent()),
|
||||
);
|
||||
const activeConfiguredNodes = createMemo(() => {
|
||||
switch (activeAgent()) {
|
||||
case 'pve':
|
||||
return props.pveNodes();
|
||||
case 'pbs':
|
||||
return props.pbsNodes();
|
||||
case 'pmg':
|
||||
return props.pmgNodes();
|
||||
}
|
||||
});
|
||||
const hasDiscoveryTimeouts = () =>
|
||||
props.discoveryMode() === 'auto' &&
|
||||
(props.discoveryScanStatus().errors || []).some((error) => /timed out|timeout/i.test(error));
|
||||
|
||||
const openCreateNode = (type: NodeType) => {
|
||||
setPrefillNode(null);
|
||||
props.setEditingNode(null);
|
||||
props.setCurrentNodeType(type);
|
||||
props.setModalResetKey((previous) => previous + 1);
|
||||
props.setShowNodeModal(true);
|
||||
};
|
||||
|
||||
const openEditNode = (type: NodeType, node: NodeConfigWithStatus) => {
|
||||
setPrefillNode(null);
|
||||
props.setEditingNode(node);
|
||||
props.setCurrentNodeType(type);
|
||||
props.setShowNodeModal(true);
|
||||
};
|
||||
|
||||
const openDiscoveredNode = (server: DiscoveredServer) => {
|
||||
setPrefillNode(buildProxmoxDiscoveryPrefillNode(server));
|
||||
props.setEditingNode(null);
|
||||
props.setCurrentNodeType(server.type);
|
||||
props.setModalResetKey((previous) => previous + 1);
|
||||
props.setShowNodeModal(true);
|
||||
};
|
||||
|
||||
const closeNodeModal = () => {
|
||||
setPrefillNode(null);
|
||||
props.setShowNodeModal(false);
|
||||
props.setEditingNode(null);
|
||||
props.setModalResetKey((previous) => previous + 1);
|
||||
};
|
||||
|
||||
const handleRefreshDiscovery = async () => {
|
||||
notificationStore.info('Refreshing discovery...', 2000);
|
||||
try {
|
||||
await props.triggerDiscoveryScan({ quiet: true });
|
||||
} finally {
|
||||
await props.loadDiscoveredNodes();
|
||||
}
|
||||
};
|
||||
const state = useProxmoxSettingsPanelState(props);
|
||||
|
||||
const handleDiscoveryToggle = async (event: ToggleChangeEvent) => {
|
||||
if (props.envOverrides().discoveryEnabled || props.savingDiscoverySettings()) {
|
||||
const nextValue = await state.handleDiscoveryToggle(event.currentTarget.checked);
|
||||
if (nextValue !== event.currentTarget.checked) {
|
||||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
const success = await props.handleDiscoveryEnabledChange(event.currentTarget.checked);
|
||||
if (!success) {
|
||||
event.currentTarget.checked = props.discoveryEnabled();
|
||||
event.currentTarget.checked = nextValue;
|
||||
}
|
||||
};
|
||||
|
||||
const renderConfiguredTable = () => {
|
||||
switch (activeAgent()) {
|
||||
case 'pve':
|
||||
return (
|
||||
<PveNodesTable
|
||||
nodes={props.pveNodes()}
|
||||
stateNodes={props.agentStateResources()}
|
||||
globalTemperatureMonitoringEnabled={props.temperatureMonitoringEnabled()}
|
||||
onTestConnection={props.testNodeConnection}
|
||||
onEdit={(node) => openEditNode('pve', node)}
|
||||
onDelete={props.requestDeleteNode}
|
||||
onRefreshCluster={props.refreshClusterNodes}
|
||||
/>
|
||||
);
|
||||
case 'pbs':
|
||||
return (
|
||||
<PbsNodesTable
|
||||
nodes={props.pbsNodes()}
|
||||
statePbs={props.pbsInstances()}
|
||||
globalTemperatureMonitoringEnabled={props.temperatureMonitoringEnabled()}
|
||||
onTestConnection={props.testNodeConnection}
|
||||
onEdit={(node) => openEditNode('pbs', node)}
|
||||
onDelete={props.requestDeleteNode}
|
||||
/>
|
||||
);
|
||||
case 'pmg':
|
||||
return (
|
||||
<PmgNodesTable
|
||||
nodes={props.pmgNodes()}
|
||||
statePmg={props.pmgInstances()}
|
||||
globalTemperatureMonitoringEnabled={props.temperatureMonitoringEnabled()}
|
||||
onTestConnection={props.testNodeConnection}
|
||||
onEdit={(node) => openEditNode('pmg', node)}
|
||||
onDelete={props.requestDeleteNode}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const renderNodeModal = (type: NodeType) => (
|
||||
<Show when={props.isNodeModalVisible(type)}>
|
||||
<NodeModal
|
||||
isOpen={true}
|
||||
resetKey={props.modalResetKey()}
|
||||
onClose={closeNodeModal}
|
||||
nodeType={type}
|
||||
editingNode={
|
||||
props.editingNode()?.type === type ? (props.editingNode() ?? undefined) : undefined
|
||||
}
|
||||
prefillNode={prefillNode()?.type === type ? (prefillNode() ?? undefined) : undefined}
|
||||
securityStatus={props.securityStatus() ?? undefined}
|
||||
temperatureMonitoringEnabled={props.resolveTemperatureMonitoringEnabled(
|
||||
props.editingNode()?.type === type ? props.editingNode() : null,
|
||||
)}
|
||||
temperatureMonitoringLocked={props.temperatureMonitoringLocked()}
|
||||
savingTemperatureSetting={props.savingTemperatureSetting()}
|
||||
onToggleTemperatureMonitoring={
|
||||
props.editingNode()?.id
|
||||
? (enabled: boolean) =>
|
||||
props.handleNodeTemperatureMonitoringChange(props.editingNode()!.id, enabled)
|
||||
: props.handleTemperatureMonitoringChange
|
||||
}
|
||||
onSave={props.saveNode}
|
||||
/>
|
||||
</Show>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SettingsSectionNav
|
||||
@@ -261,27 +128,42 @@ export const ProxmoxSettingsPanel: Component<ProxmoxSettingsPanelProps> = (props
|
||||
<div class="space-y-6 mt-6">
|
||||
<div class="space-y-4">
|
||||
<ProxmoxDirectConnectionsCard
|
||||
activeAgent={activeAgent()}
|
||||
activeConfig={activeConfig()}
|
||||
activeConfiguredNodes={activeConfiguredNodes()}
|
||||
activeDiscoveredNodes={activeDiscoveredNodes()}
|
||||
configuredTable={renderConfiguredTable()}
|
||||
activeAgent={state.activeAgent()}
|
||||
activeConfig={state.activeConfig()}
|
||||
activeConfiguredNodes={state.activeConfiguredNodes()}
|
||||
activeDiscoveredNodes={state.activeDiscoveredNodes()}
|
||||
configuredTable={
|
||||
<ProxmoxConfiguredNodesTable
|
||||
activeAgent={state.activeAgent()}
|
||||
pveNodes={props.pveNodes()}
|
||||
pbsNodes={props.pbsNodes()}
|
||||
pmgNodes={props.pmgNodes()}
|
||||
agentStateResources={props.agentStateResources()}
|
||||
pbsInstances={props.pbsInstances()}
|
||||
pmgInstances={props.pmgInstances()}
|
||||
temperatureMonitoringEnabled={props.temperatureMonitoringEnabled()}
|
||||
onTestConnection={props.testNodeConnection}
|
||||
onEditNode={state.openEditNode}
|
||||
onDeleteNode={props.requestDeleteNode}
|
||||
onRefreshClusterNodes={props.refreshClusterNodes}
|
||||
/>
|
||||
}
|
||||
discoveryEnabled={props.discoveryEnabled()}
|
||||
envOverrides={props.envOverrides()}
|
||||
initialLoadComplete={props.initialLoadComplete()}
|
||||
onDiscoveryToggle={handleDiscoveryToggle}
|
||||
onOpenCreateNode={openCreateNode}
|
||||
onRefreshDiscovery={handleRefreshDiscovery}
|
||||
onOpenCreateNode={state.openCreateNode}
|
||||
onRefreshDiscovery={state.handleRefreshDiscovery}
|
||||
savingDiscoverySettings={props.savingDiscoverySettings()}
|
||||
/>
|
||||
|
||||
<Show when={props.discoveryEnabled()}>
|
||||
<ProxmoxDiscoveryResultsCard
|
||||
activeConfig={activeConfig()}
|
||||
activeDiscoveredNodes={activeDiscoveredNodes()}
|
||||
activeConfig={state.activeConfig()}
|
||||
activeDiscoveredNodes={state.activeDiscoveredNodes()}
|
||||
discoveryScanStatus={props.discoveryScanStatus()}
|
||||
hasDiscoveryTimeouts={hasDiscoveryTimeouts()}
|
||||
onOpenDiscoveredNode={openDiscoveredNode}
|
||||
hasDiscoveryTimeouts={state.hasDiscoveryTimeouts()}
|
||||
onOpenDiscoveredNode={state.openDiscoveredNode}
|
||||
/>
|
||||
</Show>
|
||||
</div>
|
||||
@@ -299,9 +181,21 @@ export const ProxmoxSettingsPanel: Component<ProxmoxSettingsPanelProps> = (props
|
||||
/>
|
||||
</Show>
|
||||
|
||||
{renderNodeModal('pve')}
|
||||
{renderNodeModal('pbs')}
|
||||
{renderNodeModal('pmg')}
|
||||
<ProxmoxNodeModalStack
|
||||
modalResetKey={props.modalResetKey()}
|
||||
prefillNode={state.prefillNode()}
|
||||
editingNodeType={props.editingNode()?.type ?? null}
|
||||
editingNode={props.editingNode}
|
||||
isNodeModalVisible={props.isNodeModalVisible}
|
||||
securityStatus={props.securityStatus()}
|
||||
resolveTemperatureMonitoringEnabled={props.resolveTemperatureMonitoringEnabled}
|
||||
temperatureMonitoringLocked={props.temperatureMonitoringLocked()}
|
||||
savingTemperatureSetting={props.savingTemperatureSetting()}
|
||||
handleNodeTemperatureMonitoringChange={props.handleNodeTemperatureMonitoringChange}
|
||||
handleTemperatureMonitoringChange={props.handleTemperatureMonitoringChange}
|
||||
saveNode={props.saveNode}
|
||||
onClose={state.closeNodeModal}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
+12
@@ -113,9 +113,12 @@ import unifiedAgentInventoryPresentationSource from '@/utils/unifiedAgentInvento
|
||||
import relayPresentationSource from '@/utils/relayPresentation.ts?raw';
|
||||
import relaySettingsPanelSource from '../RelaySettingsPanel.tsx?raw';
|
||||
import proxmoxDeleteNodeDialogSource from '../ProxmoxDeleteNodeDialog.tsx?raw';
|
||||
import proxmoxConfiguredNodesTableSource from '../ProxmoxConfiguredNodesTable.tsx?raw';
|
||||
import proxmoxDirectConnectionsCardSource from '../ProxmoxDirectConnectionsCard.tsx?raw';
|
||||
import proxmoxDiscoveryResultsCardSource from '../ProxmoxDiscoveryResultsCard.tsx?raw';
|
||||
import proxmoxNodeModalStackSource from '../ProxmoxNodeModalStack.tsx?raw';
|
||||
import proxmoxSettingsPanelSource from '../ProxmoxSettingsPanel.tsx?raw';
|
||||
import proxmoxSettingsPanelStateSource from '../useProxmoxSettingsPanelState.ts?raw';
|
||||
import relayOnboardingCardSource from '@/components/Dashboard/RelayOnboardingCard.tsx?raw';
|
||||
import generalSettingsPanelSource from '../GeneralSettingsPanel.tsx?raw';
|
||||
import networkSettingsPanelSource from '../NetworkSettingsPanel.tsx?raw';
|
||||
@@ -305,14 +308,23 @@ describe('monitored-system model guardrails', () => {
|
||||
expect(relaySettingsPanelSource).not.toContain('Loading configuration...');
|
||||
expect(proxmoxSettingsPanelSource).toContain('CalloutCard');
|
||||
expect(proxmoxSettingsPanelSource).not.toContain('Loading configuration...');
|
||||
expect(proxmoxSettingsPanelSource).toContain('./useProxmoxSettingsPanelState');
|
||||
expect(proxmoxSettingsPanelSource).toContain('./ProxmoxConfiguredNodesTable');
|
||||
expect(proxmoxSettingsPanelSource).toContain('./ProxmoxDirectConnectionsCard');
|
||||
expect(proxmoxSettingsPanelSource).toContain('./ProxmoxDiscoveryResultsCard');
|
||||
expect(proxmoxSettingsPanelSource).toContain('./ProxmoxDeleteNodeDialog');
|
||||
expect(proxmoxSettingsPanelSource).toContain('./ProxmoxNodeModalStack');
|
||||
expect(proxmoxSettingsPanelSource).not.toContain('setPrefillNode(');
|
||||
expect(proxmoxSettingsPanelSource).not.toContain('const renderConfiguredTable = () =>');
|
||||
expect(proxmoxSettingsPanelSource).not.toContain('const renderNodeModal = (type: NodeType)');
|
||||
expect(proxmoxSettingsPanelSource).not.toContain('No discovery matches for this Proxmox type yet.');
|
||||
expect(proxmoxSettingsPanelSource).not.toContain('What happens next');
|
||||
expect(proxmoxConfiguredNodesTableSource).toContain('PveNodesTable');
|
||||
expect(proxmoxDirectConnectionsCardSource).toContain('getSettingsConfigurationLoadingState');
|
||||
expect(proxmoxDiscoveryResultsCardSource).toContain('formatRelativeTime');
|
||||
expect(proxmoxDeleteNodeDialogSource).toContain('SectionHeader');
|
||||
expect(proxmoxNodeModalStackSource).toContain('<NodeModal');
|
||||
expect(proxmoxSettingsPanelStateSource).toContain('buildProxmoxDiscoveryPrefillNode');
|
||||
expect(relayOnboardingCardSource).toContain('@/utils/relayPresentation');
|
||||
expect(relayOnboardingCardSource).toContain('RELAY_ONBOARDING_TITLE');
|
||||
expect(relayOnboardingCardSource).toContain('RELAY_ONBOARDING_DESCRIPTION');
|
||||
|
||||
@@ -46,9 +46,12 @@ import organizationAccessPanelSource from '../OrganizationAccessPanel.tsx?raw';
|
||||
import organizationSharingPanelSource from '../OrganizationSharingPanel.tsx?raw';
|
||||
import organizationBillingPanelSource from '../OrganizationBillingPanel.tsx?raw';
|
||||
import proxmoxDeleteNodeDialogSource from '../ProxmoxDeleteNodeDialog.tsx?raw';
|
||||
import proxmoxConfiguredNodesTableSource from '../ProxmoxConfiguredNodesTable.tsx?raw';
|
||||
import proxmoxDirectConnectionsCardSource from '../ProxmoxDirectConnectionsCard.tsx?raw';
|
||||
import proxmoxDiscoveryResultsCardSource from '../ProxmoxDiscoveryResultsCard.tsx?raw';
|
||||
import proxmoxNodeModalStackSource from '../ProxmoxNodeModalStack.tsx?raw';
|
||||
import proxmoxSettingsPanelSource from '../ProxmoxSettingsPanel.tsx?raw';
|
||||
import proxmoxSettingsPanelStateSource from '../useProxmoxSettingsPanelState.ts?raw';
|
||||
import securityOverviewPanelSource from '../SecurityOverviewPanel.tsx?raw';
|
||||
import securityAuthPanelSource from '../SecurityAuthPanel.tsx?raw';
|
||||
import ssoProvidersPanelSource from '../SSOProvidersPanel.tsx?raw';
|
||||
@@ -101,9 +104,12 @@ const extractedModules = [
|
||||
'../useSSOProvidersState.ts',
|
||||
'../ssoProvidersModel.ts',
|
||||
'../ProxmoxSettingsPanel.tsx',
|
||||
'../ProxmoxConfiguredNodesTable.tsx',
|
||||
'../ProxmoxDeleteNodeDialog.tsx',
|
||||
'../ProxmoxDirectConnectionsCard.tsx',
|
||||
'../ProxmoxDiscoveryResultsCard.tsx',
|
||||
'../ProxmoxNodeModalStack.tsx',
|
||||
'../useProxmoxSettingsPanelState.ts',
|
||||
'../SettingsDialogs.tsx',
|
||||
'../SettingsPageShell.tsx',
|
||||
'../useDiscoverySettingsState.ts',
|
||||
@@ -317,17 +323,29 @@ describe('Settings architecture guardrails', () => {
|
||||
});
|
||||
|
||||
it('keeps the direct Proxmox settings workspace split into section owners', () => {
|
||||
expect(proxmoxSettingsPanelSource).toContain('./useProxmoxSettingsPanelState');
|
||||
expect(proxmoxSettingsPanelSource).toContain('./ProxmoxConfiguredNodesTable');
|
||||
expect(proxmoxSettingsPanelSource).toContain('./ProxmoxDirectConnectionsCard');
|
||||
expect(proxmoxSettingsPanelSource).toContain('./ProxmoxDiscoveryResultsCard');
|
||||
expect(proxmoxSettingsPanelSource).toContain('./ProxmoxDeleteNodeDialog');
|
||||
expect(proxmoxSettingsPanelSource).toContain('./ProxmoxNodeModalStack');
|
||||
expect(proxmoxSettingsPanelSource).not.toContain('const renderConfiguredTable = () =>');
|
||||
expect(proxmoxSettingsPanelSource).not.toContain('const renderNodeModal = (type: NodeType)');
|
||||
expect(proxmoxSettingsPanelSource).not.toContain('No discovery matches for this Proxmox type yet.');
|
||||
expect(proxmoxSettingsPanelSource).not.toContain('What happens next');
|
||||
expect(proxmoxConfiguredNodesTableSource).toContain('PveNodesTable');
|
||||
expect(proxmoxConfiguredNodesTableSource).toContain('PbsNodesTable');
|
||||
expect(proxmoxConfiguredNodesTableSource).toContain('PmgNodesTable');
|
||||
expect(proxmoxDirectConnectionsCardSource).toContain('getSettingsConfigurationLoadingState');
|
||||
expect(proxmoxDiscoveryResultsCardSource).toContain('Discovery issues:');
|
||||
expect(proxmoxDiscoveryResultsCardSource).toContain(
|
||||
'No discovery matches for this Proxmox type yet. You can still add a direct',
|
||||
);
|
||||
expect(proxmoxDeleteNodeDialogSource).toContain('What happens next');
|
||||
expect(proxmoxNodeModalStackSource).toContain('PROXMOX_NODE_TYPES');
|
||||
expect(proxmoxNodeModalStackSource).toContain('<NodeModal');
|
||||
expect(proxmoxSettingsPanelStateSource).toContain('export function useProxmoxSettingsPanelState');
|
||||
expect(proxmoxSettingsPanelStateSource).toContain("notificationStore.info('Refreshing discovery...'");
|
||||
});
|
||||
|
||||
it('uses lazy() imports for panel components in settingsPanelRegistry', async () => {
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
import { createMemo, createSignal } from 'solid-js';
|
||||
import { notificationStore } from '@/stores/notifications';
|
||||
import {
|
||||
buildProxmoxDiscoveryPrefillNode,
|
||||
getProxmoxVariantPresentation,
|
||||
} from '@/utils/proxmoxSettingsPresentation';
|
||||
import type { NodeConfig, NodeConfigWithStatus } from '@/types/nodes';
|
||||
import type { DiscoveredServer, NodeType } from './useInfrastructureSettingsState';
|
||||
import type { ProxmoxSettingsPanelProps } from './ProxmoxSettingsPanel';
|
||||
|
||||
export function useProxmoxSettingsPanelState(props: ProxmoxSettingsPanelProps) {
|
||||
const [prefillNode, setPrefillNode] = createSignal<Partial<NodeConfig> | null>(null);
|
||||
|
||||
const activeAgent = () => props.selectedAgent();
|
||||
const activeConfig = createMemo(() => getProxmoxVariantPresentation(activeAgent()));
|
||||
const activeDiscoveredNodes = createMemo(() =>
|
||||
props.discoveredNodes().filter((node) => node.type === activeAgent()),
|
||||
);
|
||||
const activeConfiguredNodes = createMemo(() => {
|
||||
switch (activeAgent()) {
|
||||
case 'pve':
|
||||
return props.pveNodes();
|
||||
case 'pbs':
|
||||
return props.pbsNodes();
|
||||
case 'pmg':
|
||||
return props.pmgNodes();
|
||||
}
|
||||
});
|
||||
const hasDiscoveryTimeouts = () =>
|
||||
props.discoveryMode() === 'auto' &&
|
||||
(props.discoveryScanStatus().errors || []).some((error) => /timed out|timeout/i.test(error));
|
||||
|
||||
const openCreateNode = (type: NodeType) => {
|
||||
setPrefillNode(null);
|
||||
props.setEditingNode(null);
|
||||
props.setCurrentNodeType(type);
|
||||
props.setModalResetKey((previous) => previous + 1);
|
||||
props.setShowNodeModal(true);
|
||||
};
|
||||
|
||||
const openEditNode = (type: NodeType, node: NodeConfigWithStatus) => {
|
||||
setPrefillNode(null);
|
||||
props.setEditingNode(node);
|
||||
props.setCurrentNodeType(type);
|
||||
props.setShowNodeModal(true);
|
||||
};
|
||||
|
||||
const openDiscoveredNode = (server: DiscoveredServer) => {
|
||||
setPrefillNode(buildProxmoxDiscoveryPrefillNode(server));
|
||||
props.setEditingNode(null);
|
||||
props.setCurrentNodeType(server.type);
|
||||
props.setModalResetKey((previous) => previous + 1);
|
||||
props.setShowNodeModal(true);
|
||||
};
|
||||
|
||||
const closeNodeModal = () => {
|
||||
setPrefillNode(null);
|
||||
props.setShowNodeModal(false);
|
||||
props.setEditingNode(null);
|
||||
props.setModalResetKey((previous) => previous + 1);
|
||||
};
|
||||
|
||||
const handleRefreshDiscovery = async () => {
|
||||
notificationStore.info('Refreshing discovery...', 2000);
|
||||
try {
|
||||
await props.triggerDiscoveryScan({ quiet: true });
|
||||
} finally {
|
||||
await props.loadDiscoveredNodes();
|
||||
}
|
||||
};
|
||||
|
||||
const handleDiscoveryToggle = async (enabled: boolean) => {
|
||||
if (props.envOverrides().discoveryEnabled || props.savingDiscoverySettings()) {
|
||||
return props.discoveryEnabled();
|
||||
}
|
||||
|
||||
const success = await props.handleDiscoveryEnabledChange(enabled);
|
||||
return success ? enabled : props.discoveryEnabled();
|
||||
};
|
||||
|
||||
return {
|
||||
activeAgent,
|
||||
activeConfig,
|
||||
activeConfiguredNodes,
|
||||
activeDiscoveredNodes,
|
||||
closeNodeModal,
|
||||
handleDiscoveryToggle,
|
||||
handleRefreshDiscovery,
|
||||
hasDiscoveryTimeouts,
|
||||
openCreateNode,
|
||||
openDiscoveredNode,
|
||||
openEditNode,
|
||||
prefillNode,
|
||||
};
|
||||
}
|
||||
@@ -198,6 +198,9 @@ import pmgThreatPresentationSource from '@/utils/pmgThreatPresentation.ts?raw';
|
||||
import pmgQueuePresentationSource from '@/utils/pmgQueuePresentation.ts?raw';
|
||||
import pmgServiceHealthBadgeSource from '@/components/PMG/ServiceHealthBadge.tsx?raw';
|
||||
import proxmoxSettingsPanelSource from '@/components/Settings/ProxmoxSettingsPanel.tsx?raw';
|
||||
import proxmoxConfiguredNodesTableSource from '@/components/Settings/ProxmoxConfiguredNodesTable.tsx?raw';
|
||||
import proxmoxNodeModalStackSource from '@/components/Settings/ProxmoxNodeModalStack.tsx?raw';
|
||||
import proxmoxSettingsPanelStateSource from '@/components/Settings/useProxmoxSettingsPanelState.ts?raw';
|
||||
import infrastructureWorkspaceSource from '@/components/Settings/InfrastructureWorkspace.tsx?raw';
|
||||
import infrastructureWorkspaceModelSource from '@/components/Settings/infrastructureWorkspaceModel.ts?raw';
|
||||
import proxmoxSettingsPresentationSource from '@/utils/proxmoxSettingsPresentation.ts?raw';
|
||||
@@ -2143,10 +2146,19 @@ describe('frontend resource type boundaries', () => {
|
||||
expect(pmgThreatPresentationSource).toContain('export function getPMGThreatPresentation');
|
||||
expect(pmgQueuePresentationSource).toContain('export function getPMGQueueTextClass');
|
||||
expect(pmgServiceHealthBadgeSource).toContain('getServiceHealthPresentation');
|
||||
expect(proxmoxSettingsPanelSource).toContain('getProxmoxVariantPresentation');
|
||||
expect(proxmoxSettingsPanelSource).toContain('buildProxmoxDiscoveryPrefillNode');
|
||||
expect(proxmoxSettingsPanelSource).toContain('./useProxmoxSettingsPanelState');
|
||||
expect(proxmoxSettingsPanelSource).not.toContain('const VARIANT_CONFIG: Record<NodeType');
|
||||
expect(proxmoxSettingsPanelSource).not.toContain('const buildDiscoveryPrefillNode =');
|
||||
expect(proxmoxSettingsPanelSource).toContain('./useProxmoxSettingsPanelState');
|
||||
expect(proxmoxSettingsPanelSource).not.toContain('const openCreateNode = (type: NodeType) =>');
|
||||
expect(proxmoxSettingsPanelSource).not.toContain('const openDiscoveredNode = (server: DiscoveredServer) =>');
|
||||
expect(proxmoxConfiguredNodesTableSource).toContain('PveNodesTable');
|
||||
expect(proxmoxConfiguredNodesTableSource).toContain('PbsNodesTable');
|
||||
expect(proxmoxConfiguredNodesTableSource).toContain('PmgNodesTable');
|
||||
expect(proxmoxNodeModalStackSource).toContain('PROXMOX_NODE_TYPES');
|
||||
expect(proxmoxSettingsPanelStateSource).toContain('export function useProxmoxSettingsPanelState');
|
||||
expect(proxmoxSettingsPanelStateSource).toContain('getProxmoxVariantPresentation');
|
||||
expect(proxmoxSettingsPanelStateSource).toContain('buildProxmoxDiscoveryPrefillNode');
|
||||
expect(proxmoxSettingsPresentationSource).toContain(
|
||||
'export const PROXMOX_VARIANT_PRESENTATION',
|
||||
);
|
||||
|
||||
@@ -1890,6 +1890,11 @@ class CanonicalCompletionGuardTest(unittest.TestCase):
|
||||
"frontend-modern/src/components/Settings/InfrastructureDirectConnectionsSummaryCard.tsx"
|
||||
)
|
||||
|
||||
def test_proxmox_settings_panel_state_change_requires_agent_lifecycle(self):
|
||||
self._assert_direct_proxmox_workspace_change_requires_agent_lifecycle(
|
||||
"frontend-modern/src/components/Settings/useProxmoxSettingsPanelState.ts"
|
||||
)
|
||||
|
||||
def test_agent_install_backend_change_requires_lifecycle_and_api_contracts(self):
|
||||
required = infer_impacted_subsystems(["internal/api/agent_install_command_shared.go"])
|
||||
self.assertEqual(set(required), {"agent-lifecycle", "api-contracts"})
|
||||
|
||||
@@ -1329,6 +1329,42 @@ class SubsystemLookupTest(unittest.TestCase):
|
||||
],
|
||||
)
|
||||
|
||||
def test_lookup_paths_assigns_proxmox_settings_panel_state_to_agent_lifecycle(self) -> None:
|
||||
result = lookup_paths(
|
||||
["frontend-modern/src/components/Settings/useProxmoxSettingsPanelState.ts"]
|
||||
)
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
self.assertEqual(
|
||||
{item["subsystem"] for item in result["impacted_subsystems"]},
|
||||
{"agent-lifecycle"},
|
||||
)
|
||||
file_entry = result["files"][0]
|
||||
self.assertEqual(file_entry["classification"], "runtime")
|
||||
self.assertEqual(
|
||||
{match["subsystem"] for match in file_entry["matches"]},
|
||||
{"agent-lifecycle"},
|
||||
)
|
||||
match = file_entry["matches"][0]
|
||||
self.assertEqual(
|
||||
match["contract"],
|
||||
"docs/release-control/v6/internal/subsystems/agent-lifecycle.md",
|
||||
)
|
||||
self.assertEqual(match["lane_context"]["lane_id"], "L16")
|
||||
self.assertEqual(
|
||||
match["verification_requirement"]["id"],
|
||||
"direct-proxmox-workspace-surface",
|
||||
)
|
||||
self.assertEqual(
|
||||
match["verification_requirement"]["exact_files"],
|
||||
[
|
||||
"frontend-modern/src/components/Settings/__tests__/InfrastructureWorkspace.test.tsx",
|
||||
"frontend-modern/src/components/Settings/__tests__/UnifiedAgents.test.tsx",
|
||||
"frontend-modern/src/components/Settings/__tests__/monitoredSystemModelGuardrails.test.ts",
|
||||
"frontend-modern/src/components/Settings/__tests__/settingsArchitecture.test.ts",
|
||||
"frontend-modern/src/utils/__tests__/frontendResourceTypeBoundaries.test.ts",
|
||||
],
|
||||
)
|
||||
|
||||
def test_lookup_paths_reports_agent_install_backend_as_shared_boundary(self) -> None:
|
||||
result = lookup_paths(["internal/api/agent_install_command_shared.go"])
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
|
||||
Reference in New Issue
Block a user