Skip to content
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

Datagrid Panel: Edit data within your dashboards #66353

Merged
merged 50 commits into from
Apr 24, 2023
Merged

Conversation

mdvictor
Copy link
Contributor

What is this feature?

Introduces the datagrid panel. A new spreadsheet-like view in which users can edit data within grafana and use it in their panels.

Why do we need this feature?

Provides a new way of interacting with a dataset, where users may fine-tune their data before usage. This would prove beneficial to users working a lot with spreadsheets since they will now be able to do their editing within grafana and be more productive.

Who is this feature for?

Users that mostly use spreadsheets and spreadsheet-related datasources to pull their data in grafana.

Which issue(s) does this PR fix?:

Fixes #

Special notes for your reviewer:

Please check that:

  • It works as expected from a user's perspective.
  • If this is a pre-GA feature, it is behind a feature toggle.
  • The docs are updated, and if this is a notable improvement, it's added to our What's New doc.

Comment on lines 53 to 60
const [columnWidths, setColumnWidths] = useState<Map<number, number>>(new Map());
const [columns, setColumns] = useState<SizedGridColumn[]>([]);
const [contextMenuData, setContextMenuData] = useState<DatagridContextMenuData>({ isContextMenuOpen: false });
const [renameColumnInputData, setRenameColumnInputData] = useState<RenameColumnInputData>({ isInputOpen: false });
const [gridSelection, setGridSelection] = useState<GridSelection>(EMPTY_GRID_SELECTION);
const [columnFreezeIndex, setColumnFreezeIndex] = useState<number>(0);
const [toggleSearch, setToggleSearch] = useState<boolean>(false);
const [isResizeInProgress, setIsResizeInProgress] = useState<boolean>(false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would try to find a way to move state and logic outside the react componet (using useReducer, or StateManagerBase) or external hook. Easier to unit test state and callback logic and makes it easier to reason about the react rendering logic

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't forget unit tests for such a big and complex component (and state logic)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with you on state logic. Testing is underway for this, but I wanted to get eyes on it as soon as possible.

[FieldType.other, GridColumnIcon.HeaderReference],
]);

if (!frame) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would move this early return to before the typeToIconMap declaration, that way, we don't define something that possibly won't be used anyway.


const value = field.values.get(row);

switch (field.type) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you considered using an object here instead? iirc switches run linearly, and object key lookups execute in constant time. Plus, I think it'd be easier to test/maintain? Just a thought.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

interesting, would be curious to see some benchmarks showing this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked more into it, maybe lookups are NOT faster in modern browsers? -> https://jsben.ch/JYZLQ

I'm surprised!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm surprised!

that's the lesson here. any benchmark that's > 6mo old has to be re-evaluated. JITs improve all the time. i've seen a lot 🤯 code because some old benchmark showed that the straightforward code was slower 2yrs ago.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually i think the slowness here is mostly from the lookup version doing function calls, which will always add overhead vs basic constructs like switch and for (vs forEach)

@github-actions
Copy link
Contributor

github-actions bot commented Apr 21, 2023

Backend code coverage report for PR #66353
No changes

@github-actions
Copy link
Contributor

github-actions bot commented Apr 21, 2023

Frontend code coverage report for PR #66353

Plugin Main PR Difference
explore 86.11% 86.11% 0%
elasticsearch 78.43% 78.43% 0%
loki 84.65% 84.65% 0%

Copy link
Contributor Author

@mdvictor mdvictor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@torkelo, @zoltanbedi found a couple things I would appreciate your input on.

if (typeof toBeConverted !== 'string') {
toBeConverted = String(toBeConverted);
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are situations where values are not string in a string field type. e.g: when drag/dropping and csv the dataframe string fields can have both numeric and strings, thus the need for a conversion here. Not sure if fixing it in the convert transformer is the way to go, I think a better approach is to try to convert values when importing, maybe.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

refactored this a bit

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm okay with this. Would be nice to have a test for your use case as well.


newFrame.fields.map((field) => {
field.values = new ArrayVector([...field.values.toArray(), null]);
});
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The field values have been modified recently and the received field values aren't ArrayVectors anymore, but ArrayPropertyVector's. I'm not sure why it has changed but the entire datagrid is built around arrayVectors and changing the functionality now is not feasible.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a TODO message to follow up on this.

@mdvictor mdvictor requested a review from torkelo April 24, 2023 07:14
@mdvictor mdvictor enabled auto-merge (squash) April 24, 2023 13:32
@mdvictor mdvictor merged commit efd0e9c into main Apr 24, 2023
@mdvictor mdvictor deleted the mdvictor/datagrid branch April 24, 2023 14:46
@zerok zerok modified the milestones: 10.0.0, 10.0.0-preview May 31, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants