add the feature for sorting agent table and searching by name ! - #722
add the feature for sorting agent table and searching by name !#722Rupam-It wants to merge 8 commits into
Conversation
Signed-off-by: Rupam-It <mannarupam3@gmail.com>
Signed-off-by: Rupam-It <mannarupam3@gmail.com>
antoninbas
left a comment
There was a problem hiding this comment.
some initial comments
There was a problem hiding this comment.
aren't the logos backwards?
this one should be descending because it goes from larger at the top to smaller at the bottom
| </g> | ||
| </svg> | ||
| ); | ||
| } No newline at end of file |
There was a problem hiding this comment.
add missing newline character
|
|
||
| function ComponentSummary<T>(props: {title: string, data: T[], propertyNames: Property[], getProperties: (x: T) => string[]}) { | ||
| const itemsPerPage = 10; // Display 10 items per page for Agents table | ||
| const isAgentTable = props.title === 'Agents'; |
There was a problem hiding this comment.
rather than this, could we have a "sortable" property?
| ); | ||
| } | ||
|
|
||
| function generateFakeAgents(n: number): AgentInfo[] { |
There was a problem hiding this comment.
you should add unit tests in summary.test.tsx for the new sorting feature. The tests can use the synthetic data that you have here.
as a matter of fact, I think the test file already has some helper functions potentially to help with synthetic data generation?
| // If in development mode, generate fake agent data for UI testing | ||
| if (import.meta.env.DEV) { |
There was a problem hiding this comment.
Even in development mode, one usually connects to an actual K8s cluster and wants real agent data?
I understand that this is convenient, as usually the test clusters used for development are small and don't have a large number of Nodes / agents. So I think we can keep it, but 1) the generation of the synthetic data should be in a separate file if possible for readability, 2) this should be driven by a variable that can be set in .env.development / .env.development.local. You could set the variable in .env.development for reference, but it should be commented out by default. I don't know if there is a better / more standard way of doing it.
| const isAgentTable = props.title === 'Agents'; | ||
|
|
||
| const [currentPage, setCurrentPage] = useState(1); | ||
| const [sortConfig, setSortConfig] = useState<SortConfig | null>(null); |
There was a problem hiding this comment.
assuming my understanding of the code is correct, by default there is no sorting (which is the current behavior)?
Signed-off-by: Rupam-It <mannarupam3@gmail.com>
|
Hey @antoninbas ,
|
Signed-off-by: Rupam-It <mannarupam3@gmail.com>
Signed-off-by: Rupam-It <mannarupam3@gmail.com>
|
I also have test in the web page !
|
| VITE_API_SERVER=http://localhost:8080 | ||
|
|
||
| # Uncomment the line below to enable fakeData(agent name) in development mode | ||
| VITE_USE_SYNTHETIC_DATA=true |
There was a problem hiding this comment.
remember to comment the line out for the code you check in
| @@ -1 +1,4 @@ | |||
| VITE_API_SERVER=http://localhost:8080 | |||
|
|
|||
| # Uncomment the line below to enable fakeData(agent name) in development mode | |||
There was a problem hiding this comment.
| # Uncomment the line below to enable fakeData(agent name) in development mode | |
| # Uncomment the line below to enable synthetic Agent data in development mode. |
| export function generateFakeAgents(n: number): AgentInfo[] { | ||
| // Helper function to generate random agent names | ||
| const generateAgentName = () => { | ||
| const prefixes = ['antrea', 'k8s', 'node', 'worker', 'master']; |
There was a problem hiding this comment.
Please avoid using "master", and prefer more inclusive terminology
| const prefixes = ['antrea', 'k8s', 'node', 'worker', 'master']; | ||
| const suffixes = ['-agent', '-node', '-vm', '-host', '']; | ||
| const prefix = prefixes[Math.floor(Math.random() * prefixes.length)]; | ||
| const suffix = suffixes[Math.floor(Math.random() * suffixes.length)]; | ||
| const id = Math.random() < 0.3 ? | ||
| Math.random().toString(36).substring(2, 6) : // alphanumeric | ||
| Math.floor(Math.random() * 1000).toString(); // numeric | ||
| return `${prefix}${suffix}-${id}`; |
There was a problem hiding this comment.
I don't understand the value of having such "complicated" code for generating agent names?
why not simply use k8s-node-control-plane-1, k8s-node-worker-1, k8s-node-worker-2, ...?
| const major = Math.floor(Math.random() * 3); | ||
| const minor = Math.floor(Math.random() * 10); | ||
| const patch = Math.floor(Math.random() * 20); | ||
| return `v${major}.${minor}.${patch}`; |
There was a problem hiding this comment.
here again, I see little value in having totally random version numbers
I would actually suggest having 2 possible different version numbers (e.g., 2.2.3 and 2.3.0), which would be representative of what you could have when you are in the middle of updating Antrea in a large cluster
| return `v${major}.${minor}.${patch}`; | ||
| }; | ||
|
|
||
| // Helper function to generate random timestamps within last 30 days |
There was a problem hiding this comment.
probably much too large of a window when it comes to the heartbeat timestamp, maybe use 5 minutes instead of 30 days?
| const generateSubnets = () => { | ||
| const count = Math.floor(Math.random() * 3) + 1; // 1-3 subnets | ||
| const subnets = []; | ||
| for (let i = 0; i < count; i++) { | ||
| const ipv4 = `${Math.floor(Math.random() * 255)}.${Math.floor(Math.random() * 255)}.${Math.floor(Math.random() * 255)}.0`; | ||
| const ipv6 = `fd${Math.random().toString(16).substr(2, 2)}:${Math.random().toString(16).substr(2, 4)}::`; | ||
| subnets.push(Math.random() > 0.5 ? `${ipv4}/24` : `${ipv6}/64`); | ||
| } | ||
| return subnets; |
There was a problem hiding this comment.
here as well, please use something more representative than a random subnet, you can use consecutive subnets
| }; | ||
|
|
||
| // Helper function to generate OVS version | ||
| const generateOVSVersion = () => { |
There was a problem hiding this comment.
same comment as above (for the Antrea version)
| const isAgentTable = props.title === 'Agents'; | ||
|
|
||
| const [currentPage, setCurrentPage] = useState(1); | ||
| const [sortConfig, setSortConfig] = useState<SortConfig | null>(null); |
| const aValue = getProperties(a)[sortKeyIndex]; | ||
| const bValue = getProperties(b)[sortKeyIndex]; | ||
|
|
||
| // Custom numerical sort for 'Name' column (agent-N) |
There was a problem hiding this comment.
this is not good, once you start doing that the ComponentSummary is not generic at all anymore
either you have to use default string sorting (lexicographic) for all properties, or you need to update getProperties so that it's not limited to returning an array of strings. Maybe it could return (string | number | someType)[] and then the sorting logic would be different based on the type?
There was a problem hiding this comment.
if we sort every thing as a string then
after node-1 come node-10 not node-2!
as i have already implemented that string+num sorting !
so in our logic node-2 will comes after node-1 as it is more acceptable to all !
what's your thought?
|
#722 (comment)
Made node names match agent names for consistency 2. Made ComponentSummary Truly Generic
Control-plane nodes appear before worker nodes
see this video for more clearness! |
…akeData, added type-based sorting and better code maintainability. Signed-off-by: Rupam-It <mannarupam3@gmail.com>
Signed-off-by: Rupam-It <mannarupam3@gmail.com>
| const generateOVSVersion = () => { | ||
| // Only two possible OVS versions to simulate a cluster during upgrade | ||
| return actualIndex % 4 === 0 ? '3.0.0' : '2.17.3'; | ||
| }; |
There was a problem hiding this comment.
you should generate the Antrea version and OVS version at the same time, because there should be a 1-1 mapping between them
| // Generate sequential IPv4 subnets | ||
| if (count > 0) { | ||
| // Base subnet with sequential third octet | ||
| subnets.push(`10.10.${actualIndex % 255}.0/24`); | ||
| } | ||
|
|
||
| // Add IPv6 subnet for some nodes | ||
| if (count > 1) { | ||
| // Sequential IPv6 subnets | ||
| subnets.push(`fd00:10:10:${actualIndex % 100}::/64`); | ||
| } |
There was a problem hiding this comment.
All Nodes should have "consistent" subnets (e.g., a single IPv4 subnet, or one IPv4 subnet + one IPv6 subnet).
I don't think it's worth having an error case here (Node missing subnet)
| // Generate sequential IPv4 subnets | ||
| if (count > 0) { | ||
| // Base subnet with sequential third octet | ||
| subnets.push(`10.10.${actualIndex % 255}.0/24`); |
There was a problem hiding this comment.
If you have too many fake agents, you will have duplicate subnets. Should there be an assertion to limit the number of agents?
|
|
||
| # Uncomment the line below to enable synthetic Agent data in development mode. | ||
| # VITE_USE_SYNTHETIC_DATA=true | ||
|
|
| // Helper function to extract node type and numeric suffix for proper sorting | ||
| function getNodeNameSortValue(name: string): [string, number] { | ||
| // Match patterns like "k8s-node-worker-123" or "k8s-node-control-plane-1" | ||
| const match = name.match(/^(.*?)(control-plane|worker)-(\d+)$/); | ||
| if (match) { | ||
| // Extract the node type and number | ||
| const prefix = match[1]; | ||
| const nodeType = match[2]; // 'control-plane' or 'worker' | ||
| const numericPart = parseInt(match[3], 10); | ||
|
|
||
| // Return as tuple with nodeType first (for primary sorting) and number second | ||
| // This ensures control-plane comes before worker when sorting | ||
| return [nodeType, numericPart]; | ||
| } | ||
| // Fall back to a default value if pattern doesn't match | ||
| return ['unknown', 0]; |
There was a problem hiding this comment.
why even have a specific pattern here? this won't match most clusters
the code should be generic
| { display: agent.metadata.name, sortValue: getNodeNameSortValue(agent.metadata.name) }, | ||
| { display: agent?.version ?? 'Unknown', sortValue: agent?.version ?? 'Unknown' }, | ||
| { display: refToString(agent.podRef), sortValue: refToString(agent.podRef) }, | ||
| { display: refToString(agent.nodeRef), sortValue: refToString(agent.nodeRef) }, | ||
| { display: localPodNum.toString(), sortValue: localPodNum }, | ||
| { display: agent.nodeSubnets?.join(',') ?? 'None', sortValue: agent.nodeSubnets?.join(',') ?? 'None' }, | ||
| { display: agent?.ovsInfo?.version ?? 'Unknown', sortValue: agent?.ovsInfo?.version ?? 'Unknown' }, | ||
| { display: healthy, sortValue: healthy }, | ||
| { display: lastHeartbeat, sortValue: new Date(lastHeartbeat) }, |
There was a problem hiding this comment.
You didn't reply to my original comment (#722 (comment)), so I don't know your thought process, but I don't think this is better than sorting purely based on the value type
There was a problem hiding this comment.
so , i have write the sorting logic more refine you can take a look now!
…e the hard coded name form the agent name Signed-off-by: Rupam-It <mannarupam3@gmail.com>

#310
added feature