feat(FN-3509): document node mapping availability UI in dashboard guide
Documents the node mapping availability UI in the dashboard guide. Fusion-Task-Id: FN-3509
This commit is contained in:
@@ -1,75 +1,55 @@
|
||||
/**
|
||||
* Node-Project Assignment Utilities
|
||||
*
|
||||
* Provides canonical counting logic for projects routed to a node.
|
||||
*
|
||||
* **Runtime Behavior:**
|
||||
* - Projects with `nodeId` pointing to a remote node → run on that remote node
|
||||
* - Projects with `nodeId` pointing to a local node → run on that local node
|
||||
* - Projects without `nodeId` (unassigned) → run on local in-process runtime
|
||||
*
|
||||
* **Counting Rules:**
|
||||
* - Local nodes: include both explicitly-assigned projects AND unassigned projects
|
||||
* - Remote nodes: include only explicitly-assigned projects
|
||||
*/
|
||||
import type { NodeInfo, ProjectInfoWithSource, ProjectNodeAvailability } from "../api";
|
||||
|
||||
import type { NodeInfo, ProjectInfo } from "../api";
|
||||
|
||||
/**
|
||||
* Check if a project is routed to a specific node based on runtime rules.
|
||||
*
|
||||
* @param project - The project to check
|
||||
* @param node - The node to check against
|
||||
* @returns true if the project runs on this node
|
||||
*/
|
||||
export function isProjectRoutedToNode(project: ProjectInfo, node: NodeInfo): boolean {
|
||||
if (node.type === "remote") {
|
||||
// Remote nodes: only explicit assignment counts
|
||||
return project.nodeId === node.id;
|
||||
}
|
||||
|
||||
// Local nodes: explicit assignment OR unassigned (null/undefined)
|
||||
if (project.nodeId === node.id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Unassigned projects run on local in-process runtime
|
||||
if (project.nodeId === undefined || project.nodeId === null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
function isNonEmptyString(value: unknown): value is string {
|
||||
return typeof value === "string" && value.trim().length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all projects that are routed to a specific node.
|
||||
*
|
||||
* @param projects - All projects
|
||||
* @param node - The node to filter by
|
||||
* @returns Projects routed to this node
|
||||
*/
|
||||
export function getProjectsForNode(projects: ProjectInfo[], node: NodeInfo): ProjectInfo[] {
|
||||
return projects.filter((project) => isProjectRoutedToNode(project, node));
|
||||
export function getNodeMappingsForProject(project: ProjectInfoWithSource): ProjectNodeAvailability[] {
|
||||
const mappings = project.nodeMappings ?? [];
|
||||
return mappings
|
||||
.filter((mapping) => isNonEmptyString(mapping.nodeId) && isNonEmptyString(mapping.path))
|
||||
.map((mapping) => ({
|
||||
nodeId: mapping.nodeId,
|
||||
nodeName: mapping.nodeName,
|
||||
path: mapping.path,
|
||||
available: mapping.available !== false,
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the count of projects routed to a specific node.
|
||||
*
|
||||
* @param projects - All projects
|
||||
* @param node - The node to count projects for
|
||||
* @returns Number of projects on this node
|
||||
*/
|
||||
export function getProjectCountForNode(projects: ProjectInfo[], node: NodeInfo): number {
|
||||
export function getAvailableNodeMappingsForNode(
|
||||
project: ProjectInfoWithSource,
|
||||
node: NodeInfo,
|
||||
): ProjectNodeAvailability[] {
|
||||
return getNodeMappingsForProject(project).filter(
|
||||
(mapping) => mapping.nodeId === node.id && mapping.available,
|
||||
);
|
||||
}
|
||||
|
||||
export function isProjectAvailableOnNode(project: ProjectInfoWithSource, node: NodeInfo): boolean {
|
||||
return getAvailableNodeMappingsForNode(project, node).length > 0;
|
||||
}
|
||||
|
||||
export function getProjectsForNode(projects: ProjectInfoWithSource[], node: NodeInfo): ProjectInfoWithSource[] {
|
||||
return projects.filter((project) => isProjectAvailableOnNode(project, node));
|
||||
}
|
||||
|
||||
export function getProjectCountForNode(projects: ProjectInfoWithSource[], node: NodeInfo): number {
|
||||
return getProjectsForNode(projects, node).length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the count of unassigned projects (projects without nodeId).
|
||||
* These projects run on the local in-process runtime.
|
||||
*
|
||||
* @param projects - All projects
|
||||
* @returns Number of unassigned projects
|
||||
*/
|
||||
export function getUnassignedProjectCount(projects: ProjectInfo[]): number {
|
||||
return projects.filter((project) => project.nodeId === undefined || project.nodeId === null).length;
|
||||
export function resolveNodeDisplayName(
|
||||
nodeId: string,
|
||||
mapping: ProjectNodeAvailability | undefined,
|
||||
nodes: NodeInfo[],
|
||||
project: ProjectInfoWithSource,
|
||||
): string {
|
||||
const nodeMatch = nodes.find((node) => node.id === nodeId);
|
||||
if (nodeMatch?.name) return nodeMatch.name;
|
||||
if (mapping?.nodeName) return mapping.nodeName;
|
||||
if (project._sourceNodeName) return project._sourceNodeName;
|
||||
return nodeId;
|
||||
}
|
||||
|
||||
export function getUnassignedProjectCount(projects: ProjectInfoWithSource[]): number {
|
||||
return projects.filter((project) => getNodeMappingsForProject(project).length === 0).length;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user