-
Notifications
You must be signed in to change notification settings - Fork 712
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for generic multicolumn tables #2109
Conversation
b7b4fbd
to
9857c3a
Compare
47bcdda
to
6c93938
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very minor nits in the code.
Nicely documented PR.
Front-end side LGTM.
@@ -208,15 +213,13 @@ class NodeDetails extends React.Component { | |||
return ( | |||
<div className="node-details-content-section" key={table.id}> | |||
<div className="node-details-content-section-header"> | |||
{table.label} | |||
{table.label.length > 0 && table.label} |
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
import NodeDetailsRelatives from './node-details/node-details-relatives'; | ||
import NodeDetailsTable from './node-details/node-details-table'; | ||
import Warning from './warning'; | ||
|
||
|
||
const logError = debug('scope:error'); |
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
|
||
import { NODE_DETAILS_DATA_ROWS_DEFAULT_LIMIT } from '../../constants/limits'; | ||
import { | ||
isNumber, getTableColumnsStyles, genericTableEntryKey |
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
@@ -0,0 +1,108 @@ | |||
import React from 'react'; | |||
import { Map as makeMap } from 'immutable'; | |||
import { sortBy } from 'lodash'; |
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
super(props, context); | ||
this.state = { | ||
limit: NODE_DETAILS_DATA_ROWS_DEFAULT_LIMIT, | ||
sortedBy: props.columns[0].id, |
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
// Table is the type for a table in the UI. | ||
type Table struct { | ||
ID string `json:"id"` |
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
switch template.Type { | ||
case MulticolumnTableType: | ||
rows = node.ExtractMulticolumnTable(template) | ||
default: // By default assume it's a property list (for backward compatibility). |
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
@fbarl Really clean design and code. Did you test with an old probe, to verify there are no backwards compatibility issues? |
I've always thought that using the |
sort.Strings(ids) | ||
|
||
// Return the rows in the sorted order. | ||
rows = []Row{} |
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
}) | ||
|
||
// Gather a sorted list of rows' IDs. | ||
ids := make([]string, 0, len(rowsByID)) |
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
} | ||
sort.Strings(ids) | ||
|
||
// Return the rows in the sorted order. |
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
} | ||
}) | ||
|
||
// Gather a sorted list of labels. |
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
Does this PR happen to address #1735 too? |
6c93938
to
549bb20
Compare
@rade Not really. All the column widths are still hardcoded on the frontend, I just moved that code to a different file :) |
I tested it on a manually modified report that I linked to above, in my PR description. Out of the three nodes visible in Weave Net, one of them has everything stored in the new format, one of them in the old, and one of them both (even though that case will never happen I think). I didn't know how to test this data dynamically (without loading it from static reports), so maybe we should do that additional check somehow before pushing. What do you think?
While I was working on this story, I was gradually finding out how big of a constraint backwards compatibility is. Do you have any ideas how we could come around this in the future? |
549bb20
to
5583a5d
Compare
Your test sounds reasonable, but I would also run a standalone probe with an older version (e.g. Scope 1.1.0) to make sure everything renders as it should.
Not really (without content negotiation or versioned APIs) |
Code looks good, waiting on further backwards compatibility testing to approve. |
@fbarl Would you mind (at least partially) squashing the commits? |
5583a5d
to
0e837b6
Compare
Replaced MetadataRow with generic Row in Table model Sending through multicolumn tables from the backend
Rendering generic table columns Made Type a required attribute for TableTemplate Made generic table sortable on the UI
Extracted table headers common code on the frontend Fixed the search matching and extracted further common code in the UI
0e837b6
to
bc12ae4
Compare
Backward-compatibility fix
fb755e7
to
d3466b5
Compare
I tested it with a standalone Scope 1.1.0 as you suggested @fons and good that I did because a small change on the backend still needed to be made for backwards compatibility with old probes to work properly. I also tested it with the new probe and with mixed reports after that, but I found no problems there. So as far as I could tell, everything should be working fine after merging this PR! |
Great job @fbarl . LGTM! |
Resolves #1980. Prior to this story, we could only render Node Tables and Labels (renamed to Property Lists in this PR) in the node details panel. This PR introduces Generic Table as a separate UI component that enables us to render generic data in a multi-column format without associating rows to nodes.
Modeling
As @davkal reasoned, it makes sense to have Property Lists and Generic Tables as distinct components in the UI, so I made them fully independent there, but for backward compatibility reasons, I kept them under the old
Table
model on the backend, which I finally decided to extend like this:where
Columns
is used only with themulticolumn-table
template type andFixedRows
in only supported forproperty-list
. The main reason I decided not to support fixed rows for generic (multicolumn) tables is that it wasn't clear what the exact use-case might be and how they would be rendered in the UI.Storing
To be consistent with how property lists are being stored on the node, I decided to use the
node.Latest
map with table prefixes to store generic tables as well. The only difference is that since a multi-column table is two-dimensional, the table value is determined not only by label, but by (row, column) pair. Storing whole rows in theLatest
map was not an option for two reasons:Latest
is astring
tostring
map so we can only use it to store strings.To be able to differ between the rows, each of them has to be given an ID (instead of what used to be a label). For backward compatibility with the old reports, property lists label is indeed used as a row ID when sending a table to the UI.
Rendering in the UI
Generic table is sortable and supports different column types (sent through
Column.DataType
field on the backend). Column headers are the same as for Node Tables (they are now in a new component calledNodeDetailsTableHeaders
), and column widths can also be hard-coded on the frontend.To see this, run
fixprobe
on this reportOther Observations
node.Latest
map for every table (or a property list) we are extracting, instead of just running through the entries with a given prefix and extracting the fixed row information separately. I haven't looked into the implementation details of ourMap
structure, but maybe it wouldn't be that difficult to add an efficientForEachFromTo
kind of method there to run only on selected intervals. That would drop our time complexity of extraction roughly fromO(T * N)
toO(N + T * log N)
(orO(N * log N)
, if a lot of entries correspond to fixed rows), whereT
is the number of tables andN
is the total size ofnode.Latest
. Not sure if it's a bottleneck or if it's worth digging into this, but I just wanted to point it out.node-details
dir in the UI, likeNodeDetailsInfo
, which are both semantically and implementation-wise similar toNodeDetailsPropertyList
, so consider refactoring them in some future PR.