mirror of
https://github.com/elastic/kibana.git
synced 2025-04-25 10:23:14 -04:00
16 commits
Author | SHA1 | Message | Date | |
---|---|---|---|---|
|
b32f0fe1e8
|
[kbn-grid-layout] Store rows in object instead of array (#212965)
Closes https://github.com/elastic/kibana/issues/211930 ## Summary This PR makes it so that `kbn-grid-layout` stores its rows as an object / dictionary (`{ [key: string]: GridRowData }`) rather than an array (`Array<GridRowData>`). This is a prerequisite for https://github.com/elastic/kibana/issues/190381 , since it allows us to re-order rows without re-rendering their contents. It also means that deleting a row will no longer cause the rows below it to re-render, since re-rendering is now dependant on the row's **ID** rather than the row's order. **Before** https://github.com/user-attachments/assets/83651b24-a32c-4953-8ad5-c0eced163eb5 **After** https://github.com/user-attachments/assets/9cef6dbc-3d62-46aa-bc40-ab24fc4e5556 ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> |
||
|
e587187ffc
|
[kbn-grid-layout] Add ability to create, edit, and delete rows (#209193)
Closes https://github.com/elastic/kibana/issues/204849 ## Summary This PR adds the ability to create, edit, and delete sections / rows to `kbn-grid-layout`: https://github.com/user-attachments/assets/4831b289-2c71-42fb-851d-0925560e233a Note that sections are still statically placed - dragging rows around will be added in a follow-up PR, because it's a larger undertaking. Since this feature is not available to users yet, it is okay to implement this in stages like this. ### Checklist - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md) - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) ### Identify risks Collapsible sections are not available on Dashboard yet and so there is no user-facing risk to this PR. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Marta Bondyra <4283304+mbondyra@users.noreply.github.com> |
||
|
200922a512
|
[kbn-grid-layout] Add useCustomDragHandle prop (#210463)
This PR **might** resolve https://github.com/elastic/kibana/issues/207011 but we will need time for the telemetry metrics to settle before we know for sure. ## Summary This PR removes the conditional rendering of the default drag handle in `kbn-grid-layout`, which has two benefits: 1. It removes the double render of `GridPanel` that was caused by relying on the `dragHandleCount` to be updated in order to determine whether the default drag handle should be rendered 2. The default drag handle no longer "flashes" when Dashboards are loading and waiting for `dragHandleCount` to update - **Before:** https://github.com/user-attachments/assets/30a032fc-4df3-42ce-9494-dd7f69637c03 - **After:** https://github.com/user-attachments/assets/db447911-cbe2-40dd-9a07-405d1e35a75d Instead, the consumer of `kbn-grid-layout` is responsible for setting the `useCustomDragHandle` prop to `true` when they want to use a drag handle other than the default one. When adding the `useCustomDragHandle` prop, I got annoyed that I had to pass this prop all the way down to `grid_panel` - so I decided to swap to using React context in this PR, as well. The API for the grid layout component will most likely continue to grow, so this should make it easier to manage the props. ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) |
||
|
05916056cd
|
[embeddable] make presentation interface names consistent (#205279)
PR cleans up presentation interface names for consistentency * adds `$` suffix to all observables. For example, `dataLoading` => `dataLoading$` * removes `Panel` naming convention from interface names since an api may not be a panel, an api may be a dashboard. For example, `PublisesPanelTitle` => `PublishesTitle` #### Note to Reviewers Pay special attention to any place where your application creates an untyped API. In the example below, there is no typescript violation when the parent returns `dataLoading` instead of `dataLoading$` since the parent is not typed as `PublishesDataLoading`. Please check for instances like these. ``` <ReactEmbeddableRenderer getParentApi={() => { dataLoading: new BehaviorSubject() }} /> ``` --------- Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com> Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> |
||
|
5ee4297994
|
[Dashboard][kbn-grid-layout ] Update styles (#206503)
Closes https://github.com/elastic/kibana/issues/204060 ## Summary This PR updates the styles used for `kbn-grid-layout` in Dashboard as shown below. - **Dragging** | Before | After | |--------|--------| |  |  | |  |  | - **Resizing** | Before | After | |--------|--------| |  |  | |  |  | As part of this work, I moved all aesthetic style logic out of the `kbn-grid-layout` package and added support for Emotion to the `GridLayout` component instead - this means that the consumer is responsible for applying styles based on given classes, and `kbn-grid-layout` is now less opinionated. The only styling kept in the `kbn-grid-layout` package are those that handle layout-engine specific functionality (positioning of panels, hiding edit actions in view mode, etc). In addition, I also updated the styles used in the grid example app and added settings for dynamically changing the grid gutter size + row height: https://github.com/user-attachments/assets/c2f06db1-7041-412e-b546-86b102cc0770 ### Checklist - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md) - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) ### Identify risks This PR has minimal risk, since it is primarily style changes. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> |
||
|
686571547f
|
[Dashboard][Collapsable Panels] Swap react-grid-layout for kbn-grid-layout (#205341)
Closes https://github.com/elastic/kibana/issues/190446 ## Summary This PR swaps out `react-grid-layout` for the new internal `kbn-grid-layout` in the Dashboard plugin. This is the first major step in making collapsible sections possible in Dashboard. - **`react-grid-layout` (before)**: https://github.com/user-attachments/assets/ca6ec059-7f4a-43fb-890e-7b72b781e50b - **`kbn-grid-layout` (after)**: https://github.com/user-attachments/assets/3d3de1f3-1afc-4e6b-93d6-9cc31a46e2cf ### Notable Improvements - Better handling of resizing panels near the bottom of the screen | `react-grid-layout` | `kbn-grid-layout` | |--------|--------| |  |  | - Auto-scroll when dragging / resizing panels near the top and bottom of the screen, making it much easier to move panels around by larger distances | `react-grid-layout` | `kbn-grid-layout` | |--------|--------| |  |  | - More reliable panel positioning due to the use of CSS grid rather than absolute positioning via pixels | `react-grid-layout` | `kbn-grid-layout` | |--------|--------| |  |  | - Better performance when dragging and resizing (see https://github.com/elastic/kibana/pull/204134 for a more thorough explanation) and a smaller bundle size than `react-grid-layout` ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) ### Identify risks This PR contains a significant change to the Dashboard layout engine, which means that it carries a decent amount of risk for introducing new, uncaught bugs with dragging / resizing panels and collision resolution. That being said, `kbn-grid-layout` has been built **iteratively** with plenty of testing along the way to reduce this risk. ## Release note Improves Dashboard layout engine by switching to the internally developed `kbn-grid-layout`. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Marta Bondyra <4283304+mbondyra@users.noreply.github.com> |
||
|
2be928c489
|
SKA: Categorise remaining packages (#205875)
## Summary * Delete unused package `@kbn/formatters` * Delete unused package `@kbn/response-ops-feature-flag-service` * Flag `@kbn/generate-console-definitions` as `devOnly: true` * Flag `@kbn/plugin-check` as `devOnly: true` * Flag `@kbn/set-map` as `devOnly: true` * Flag `@kbn/synthetics-private-location` as `devOnly: true` * Categorise `@kbn/calculate-auto` as `platform/shared` * Categorise `@kbn/charts-theme` as `platform/shared` * Categorise `@kbn/saved-search-component` as `platform/shared` * Categorise `@kbn/use-tracked-promise` as `platform/shared` * Categorise `@kbn/charts-theme` as `platform/shared` * Categorise `@kbn/response-ops-rule-form` as `platform/shared` |
||
|
1ff181c5df
|
[Dashboard][Collapsable Panels] New collision resolution algorithm (#204134)
Closes https://github.com/elastic/kibana/issues/191306 ## Summary This PR updates the collision resolution algorithm to handle the edge case described in the linked issue. In the old algorithm, we checked each panel for collisions a **single time** - however, this caused a bug where panels could get re-ordered depending on the order that we pushed panels down + how much distance we were pushing them down by. While this algorithm was extremely efficient (approximately $`O \left({ { n^2 + n } \over 2 }\right)`$ before compaction where `n` is the number of panels), it was not as simple as "fixing" the bug because, no matter what, there was always an edge case that could not be handled without adding some sort of backtracking - instead, we had to come up with a new algorithm. ### Example of Edge Case To better understand how the old and new algorithms compare (and how they work), consider a scenario where the grid layout has 8 columns and the panels are laid out as follows:  Now, what happens when panel 4 (yellow) is dragged to the left so that it overlaps both panel 3 (red) and panel 4 (blue)? <details> <summary><b>Old Algorithm</b></summary> With the old algorithm, we get the following behaviour:  This is because we are **only** pushing the collided panels down **once**. So, to describe what happens in detail, we start by gathering up the panels **in order** (top-bottom, left-right, where dragged panels take priority when rows are equal) - this results in an order of `[panel4, panel3, panel1, panel2]`. We start checking for collisions in this order - starting with panel 4 (yellow), we determine that it is colliding with panel 3 (red) and panel 2 (blue). We start with panel 3 (since we are once again doing this "in order"), and we push it down by 5 rows (since this is the overlap of the panel 3 and panel 4). Then, to "resolve" the second collision with panel 4, we push down panel 2 by 3 rows. This leaves the layout in the following state:  Now, since panel 4 (yellow) is "resolved", we move on to the next panel in the `[panel4, panel3, panel1, panel2]` order - panel 3 (red). Panel 3 now collides with panel 2, so we push panel 2 down by two rows. This is the only collision with panel 3, so we check panel 1 and panel 2, neither of which report collisions at this point. So the layout ends in the following state:  So, what's the problem here? Well, panel 1 (green) is now "out of sync" with the old panel ordering because it got "left behind" in the collision resolution. Instead, we should have moved panel 1 by the same amount as panel 2. </details> <details> <summary><b>New Algorithm</b></summary> With the new algorithm, we get the expected behaviour:  If we run through the algorithm, we identify that the **first** collision in the layout (based on left to right, top to bottom ordering, with priority being the panel being dragged) is panel 4 (yellow) - so, we enter the `while` loop and recurse to resolve all collisions with panel 4 via `resolvePanelCollisions`. The recursion within `resolvePanelCollisions` works as follows - get **all** collisions with panel 4 (which, at this point, returns panel 3 (red) and panel 2 (blue)) and push them down by a single row, then recurse on **those** panels to resolve any of the resulting collisions. It's difficult to describe recursion, but let me try my best :) During the collision resolution on panel 4, we start by pushing panel 3 down and then recursively resolving the collisions on panel 3. Since pushing panel 3 causes collisions with panel 1 and 2 (in order), we push them both down by one row - starting with panel 1. We recurse to resolve the collisions on panel 1, which has no collisions - then we do the same for panel 2, which also reports no collisions. The collisions with panel 3 are "resolved" (i.e. we can "back out" of the recursion on panels 1 and 2), so we go back to resolving panel 4, push panel **2** down, and then resolve the collisions on panel 2 - which reports no collisions. In summary:  Therefore, after the first iteration of the `while` loop, this results in the following layout, where panel 3 (red) has been pushed down by one row, panel 1 (green) has been pushed down by one row, and panel 2 (blue) has been pushed down by two rows:  We then return to the `while` loop and check if the layout has any other collisions - and panel 4 is still our "first" collision! So we repeat the process above and push both panel 4 and panel 2 down and recurse to resolve the resulting collisions on those panels. This continues as follows: | Steps | Resulting Layout | |--------|--------| | <img width="400" src="https://github.com/user-attachments/assets/d2691a1c-5f0b-4333-bfd4-3cc57e1a3098"/> | <img width="400" src="https://github.com/user-attachments/assets/85325df3-7fbf-46fa-af98-10bbd883cf8d"/> | | <img width="400" src="https://github.com/user-attachments/assets/e31a400f-d0d1-408d-baec-efa708ad0c52"/> | <img width="400" src="https://github.com/user-attachments/assets/c81762d4-443b-451c-b8fc-dabaf4e32ba1"/> | | <img width="400" src="https://github.com/user-attachments/assets/4292e4a9-4157-4d77-9b69-b0f6a07338ac"/> | <img width="400" src="https://github.com/user-attachments/assets/bdd2dad5-6531-4d56-b8c2-dfb121fb6b5b"/> | | <img width="400" src="https://github.com/user-attachments/assets/6d194a89-3ed6-46a6-9dcc-2b3fa0de9942"/> | <img width="400" src="https://github.com/user-attachments/assets/7e0b0fb5-bacb-49ad-ac86-02665a779b59"/> | And so, after our fifth iteration of the `while` loop, the layout is **no longer** reporting collisions - so, our layout is now fully resolved! </details> ### Performance Comparison This algorithm is more-or-less the same as the algorithm used in `react-grid-layout` - however, instead of running on **every frame**, our layout engine only resolves collisions **as they happen** (hence why the while loop is necessary). This results in much better rendering performance. To test this, I opened the Logs sample dashboard in both the example app (which is obviously using `kbn-grid-layout`) and Dashboard (which is still using `react-grid-layout`) and performed various drag actions on both while recording their performance. For example, consider the following capture of a drag that doesn't cause **any** collisions: | `kbn-grid-layout` | `react-grid-layout` | |--------|--------| |  |  | You can see that, even with no collisions, the performance is slightly better with `kbn-grid-layout` because we don't **ever** recurse on collisions in this scenario. But it gets even better when actual collisions happen - for example, consider the performance when the dragged panel only causes a **single** collision: | `kbn-grid-layout` | `react-grid-layout` | |--------|--------| |  |  | Versus when the dragged panel causes multiple collisions at the top of the dashboard that causes a chain reaction of panels needing to be pushed down: | `kbn-grid-layout` | `react-grid-layout` | |--------|--------| |  |  | In all of the above scenarios, performance is improved overall **and** there are fewer red "spikes" / bottlenecks due to [forced reflow](https://web.dev/articles/avoid-large-complex-layouts-and-layout-thrashing?utm_source=devtools#avoid-forced-synchronous-layouts) along the way. Most of the time saved is caused by significant reductions to both `rendering` and `painting` time in `kbn-grid-layout` when compared to `react-grid-layout`. While some of this improvement may be explained by differences in the example grid plugin versus the Dashboard plugin, this is enough proof that performance of `kbn-grid-layout` is **at least as good as** `react-grid-layout` and so swapping out the layout engine should not cause any performance regressions. ### Other Notable Algorithm Attempts I tried a few **drag/resize event specific** algorithms that **only work** when an interaction event is happening - i.e. they rely on information from the panel that is being interacted with in order to function. Note that, if we decided to go this route, we would still need some generic collision resolution algorithm (such as the one proposed in this PR) that we could use to resolve a layout when **no** interaction event is happening. After all, we cannot assume that the grid layout that is sent as a prop is valid (i.e. it **could** have overlapping panels **at the start**, before any dragging and/or resizing has occurred) and we need a way to verify + resolve it. Unfortunately, both of the "interaction-event necessary" collision resolution algorithms that I tried suffered from bugs so, while it might be **possible** to make a more efficient algorithm for this, I ultimately threw them away in favour of using the "generic" collision resolution algorithm proposed in this PR. That being said, I figured it was worth documenting the things that I tried and why they failed. <details> <summary><b>Algorithm 1</b></summary> I tried a modification of the **original** collision resolution algorithm where, instead of **just** moving the colliding panels down by the `rowOverlap` amount, we move **all** panels in or below the targeted grid row down by the **height** of the panel being dragged. However, due to the compaction algorithm ignoring **all** panels that have collisions, you can end up in an infinite "push panels down" loop like so:  This is because panel 3 is **always** colliding with panel 1 and 4, so they never get pushed up to "close" the gaps. To try and get around this, I modified the collision detection used for panel compaction so that collisions only "stop" compaction if the collision occurs on a panel **above** the given panel we are trying to compact. However, this caused a **different** bug:  In the above GIF, consider what happens when panel 3 (red) targets row 3. As expected, we move all other panels (1, 2, and 4) down by a single row. Then, when we reach the compaction step, we start by trying to push panel 1 up (since it is now the top-left-most panel) - and, since we are filtering out the collision with panel 3 (since it occurs "below" panel 1), it gets pushed all the way to the top. Then, we push panel 4 all the way to the top (because it is also ignoring the collision with panel 3), followed by pushing panel 2 up until it would collide with panel 3. Unfortunately though, we didn't account for the full height of panel 4 - so panel 3 is now stuck colliding with panel 4. I modified this algorithm **further** to move the panels down by the "row overlap" with the dragged panel rather than the dragged panel's height - but this also suffers from a bug:  At which point, I abandoned this approach becase it felt like there were too many edge cases that could not all be accounted for. It's possible we could explore this further but, given the limitations of this algorithm **only working** for resolving collisions given an interaction event, I opted to move on. </details> <details> <summary><b>Algorithm 2</b></summary> I tried an algorithm where, similar to the algorithm proposed in this PR, I recorded the panel IDs in each cell that a given panel occupied - however, instead of moving things down row by row and handling the resulting collisions, we moved **every** panel that was **below** the targetted row down by the **height** of the panel being dragged. In theory, the compaction algorithm would then take control of closing all the resulting gaps. Unfortunately, this didn't quite work in practice. Consider the following:  According to the algorithm defined above, panel 2 (blue) and panel 4 (yellow) both need to move down when panel 3 (red) is dragged to target row 4 (remember that row **zero** is the first row), since they both occupy this row - so we push both of them down by 1 (the height of panel 3). However, once we start compacting the layout in order to finish our collision resolution, we hit a snag with panel 4 (yellow) - when we start trying to compact panel 4, `getAllCollisionsWithPanel` returns that **panel 3** is colliding with panel 4 and so we **break out** of the compaction - hence why panel 4 continues to float. This then has a snowball effect on all other panels as they report collisions and therefore do not get pushed up. </details> <details> <summary><b>Algorithm 3</b></summary> This was the algorithm we **almost** went with, because it works! But it suffered from two things - one, the code was complicated and difficult to maintain and two, the collision resolution behaviour felt less natural because it **always** favoured the dragged panel. This made it too sensitive to pushing items down; so even if a panel was targeting the bottom row of a different panel, it would push that panel down to make room for the dragged panel. In the simplest terms, this algorithm worked as follows: after creating a 3D array representing the current grid (a 2D array of panel ID arrays), for each row, while there are collisions, push panels down in **reverse order** (bottom right to top left); continue until all rows have no collisions. This algorithm hd an efficiency of approximately $`O\left(r * c \right)`$ to set up the 3D array and $`O \left( c * h * n \right)`$ to resolve the conflicts, where `r` is the number of rows, `c` is the number of columns (minus 1), `h` is the height of the dragged panel, and `n` is the number of panels. This results in an overall speed of about $`O \left( (r * c) + (c * h * n) \right)`$ To better understand how this algorithm works, consider how it handles the edge case described above: <details> <summary>Algorithm 3 - Edge Case Example</summary> Rather than checking every **panel** for collisions a single time, we check and resolve each **row** for collisions and resolve them. This gives the following behaviour:  We start by creating a 3D array representing the grid - at the **first** point of collision, it looks like: | | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |--------|--------|--------|--------|--------|--------|--------|--------|--------| | **0** | `[panel3]` | `[panel3]` | `[panel3]` | `[panel3, panel4]` | `[panel4]` | `[panel4]` | `[panel4]` | `[]` | | **1** | `[panel3]` | `[panel3]` | `[panel3]` | `[panel3, panel4]` | `[panel4]` | `[panel4]` | `[panel4]` | `[]` | | **2** | `[panel1]` | `[panel1]` | `[panel2]` | `[panel2, panel4]` | `[panel4]` | `[panel4]` | `[panel4]` | `[]` | | **3** | `[panel1]` | `[panel1]` | `[panel2]` | `[panel2, panel4]` | `[panel4]` | `[panel4]` | `[panel4]` | `[]` | | **4** | `[panel1]` | `[panel1]` | `[panel2]` | `[panel2, panel4]` | `[panel4]` | `[panel4]` | `[panel4]` | `[]` | Then, we start checking and resolving collisions, row by row. Starting with row 0, we see that column 3 has a collision between panel 3 and panel 4 - we **ignore** the panel being dragged (panel 4), so we push down panel 3 by one row. Row 0 has no more collisions, so we move on to row 1 and, following the same logic as above, we push down panel 3 again. This leaves the grid in the following state:  | | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |--------|--------|--------|--------|--------|--------|--------|--------|--------| | **0** | `[]` | `[]` | `[]` | `[panel4]` | `[panel4]` | `[panel4]` | `[panel4]` | `[]` | | **1** | `[]` | `[]` | `[]` | `[panel4]` | `[panel4]` | `[panel4]` | `[panel4]` | `[]` | | **2** | `[panel1, panel3]` | `[panel1, panel3]` | `[panel2, panel3]` | `[panel3, panel2, panel4]` | `[panel4]` | `[panel4]` | `[panel4]` | `[]` | | **3** | `[panel1, panel3]` | `[panel1, panel3]` | `[panel2, panel3]` | `[panel3, panel2, panel4]` | `[panel4]` | `[panel4]` | `[panel4]` | `[]` | | **4** | `[panel1]` | `[panel1]` | `[panel2]` | `[panel2, panel4]` | `[panel4]` | `[panel4]` | `[panel4]` | `[]` | Now, on row 2, we have collisions in columns zero through three, so we push the panels in **reverse order** (i.e from the bottom right to the top left) - this results in pushing panel 2 down, then panel 1, and finally panel 3. We have to add a row in order to accomplish this because otherwise we "lose" the bottom of panel 2, so our layout now looks like this and row 2 has no more collisions:  | | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |--------|--------|--------|--------|--------|--------|--------|--------|--------| | **0** | `[]` | `[]` | `[]` | `[panel4]` | `[panel4]` | `[panel4]` | `[panel4]` | `[]` | | **1** | `[]` | `[]` | `[]` | `[panel4]` | `[panel4]` | `[panel4]` | `[panel4]` | `[]` | | **2** | `[]` | `[]` | `[]` | `[panel4]` | `[panel4]` | `[panel4]` | `[panel4]` | `[]` | | **3** | `[panel1, panel3]` | `[panel1, panel3]` | `[panel2, panel3]` | `[panel3, panel2, panel4]` | `[panel4]` | `[panel4]` | `[panel4]` | `[]` | | **4** | `[panel1, panel3]` | `[panel1, panel3]` | `[panel2, panel3]` | `[panel3, panel2, panel4]` | `[panel4]` | `[panel4]` | `[panel4]` | `[]` | | **5** | `[panel1]` | `[panel1]` | `[panel2]` | `[panel2]` | `[]` | `[]` | `[]` | `[]` | Continuing this behaviour, we push panel 2, panel 1, and panel 3 down in row 3; then again in row 4. Once we reach and resolve row 5 (i.e. get row 5 to the point where there are no collisions with panel 3), our layout looks like so:  | | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |--------|--------|--------|--------|--------|--------|--------|--------|--------| | **0** | `[]` | `[]` | `[]` | `[panel4]` | `[panel4]` | `[panel4]` | `[panel4]` | `[]` | | **1** | `[]` | `[]` | `[]` | `[panel4]` | `[panel4]` | `[panel4]` | `[panel4]` | `[]` | | **2** | `[]` | `[]` | `[]` | `[panel4]` | `[panel4]` | `[panel4]` | `[panel4]` | `[]` | | **3** | `[]` | `[]` | `[]` | `[panel4]` | `[panel4]` | `[panel4]` | `[panel4]` | `[]` | | **4** | `[]` | `[]` | `[]` | `[panel4]` | `[panel4]` | `[panel4]` | `[panel4]` | `[]` | | **5** | `[panel3]` | `[panel3]` | `[panel3]` | `[panel3]` | `[]` | `[]` | `[]` | `[]` | | **6** | `[panel3, panel1]` | `[panel3, panel1]` | `[panel2, panel3]` | `[panel2, panel3]` | `[]` | `[]` | `[]` | `[]` | | **7** | `[panel1]` | `[panel1]` | `[panel2]` | `[panel2]` | `[]` | `[]` | `[]` | `[]` | | **8** | `[panel1]` | `[panel1]` | `[panel2]` | `[panel2]` | `[]` | `[]` | `[]` | `[]` | At this point, all collisions on panel 4 have been resolved. So, in row 6, we see that panels 2 and 1 are now colliding with panel 3 - so, we push both of them down. At that point, row 6 does not have collisions so we **don't** push panel 3 down any further - and our layout is resolved!  | | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |--------|--------|--------|--------|--------|--------|--------|--------|--------| | **0** | `[]` | `[]` | `[]` | `[panel4]` | `[panel4]` | `[panel4]` | `[panel4]` | `[]` | | **1** | `[]` | `[]` | `[]` | `[panel4]` | `[panel4]` | `[panel4]` | `[panel4]` | `[]` | | **2** | `[]` | `[]` | `[]` | `[panel4]` | `[panel4]` | `[panel4]` | `[panel4]` | `[]` | | **3** | `[]` | `[]` | `[]` | `[panel4]` | `[panel4]` | `[panel4]` | `[panel4]` | `[]` | | **4** | `[]` | `[]` | `[]` | `[panel4]` | `[panel4]` | `[panel4]` | `[panel4]` | `[]` | | **5** | `[panel3]` | `[panel3]` | `[panel3]` | `[panel3]` | `[]` | `[]` | `[]` | `[]` | | **6** | `[panel3]` | `[panel3]` | `[panel3]` | `[panel3]` | `[]` | `[]` | `[]` | `[]` | | **7** | `[panel1]` | `[panel1]` | `[panel2]` | `[panel2]` | `[]` | `[]` | `[]` | `[]` | | **8** | `[panel1]` | `[panel1]` | `[panel2]` | `[panel2]` | `[]` | `[]` | `[]` | `[]` | | **9** | `[panel1]` | `[panel1]` | `[panel2]` | `[panel2]` | `[]` | `[]` | `[]` | `[]` | </details> </details> ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) ### Identify risks There are no risks to this PR, since all work is contained in the `examples` plugin. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> |
||
|
99aa884fa0
|
Preparation for High Contrast Mode, Analytics Experience domains (#202608)
## Summary **Reviewers: Please test the code paths affected by this PR. See the "Risks" section below.** Part of work for enabling "high contrast mode" in Kibana. See https://github.com/elastic/kibana/issues/176219. **Background:** Kibana will soon have a user profile setting to allow users to enable "high contrast mode." This setting will activate a flag with `<EuiProvider>` that causes EUI components to render with higher contrast visual elements. Consumer plugins and packages need to be updated selected places where `<EuiProvider>` is wrapped, to pass the `UserProfileService` service dependency from the CoreStart contract. **NOTE:** **EUI currently does not yet support the high-contrast mode flag**, but support for that is expected to come in around 2 weeks. These first PRs are simply preparing the code by wiring up the `UserProvideService`. ### Checklist Check the PR satisfies following conditions. Reviewers should verify this PR satisfies this list as well. - [X] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [X] The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) ### Risks Does this PR introduce any risks? For example, consider risks like hard to test bugs, performance regression, potential of data loss. Describe the risk, its severity, and mitigation for each identified risk. Invite stakeholders and evaluate how to proceed before merging. - [ ] [medium/high] The implementor of this change did not manually test the affected code paths and relied on type-checking and functional tests to drive the changes. Code owners for this PR need to manually test the affected code paths. - [ ] [medium] The `UserProfileService` dependency comes from the CoreStart contract. If acquiring the service causes synchronous code to become asynchronous, check for race conditions or errors in rendering React components. Code owners for this PR need to manually test the affected code paths. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> |
||
|
2a76fe3ee4
|
[Dashboard] [Collapsable Panels] Add embeddable support (#198413)
Closes https://github.com/elastic/kibana/issues/190379 ## Summary This PR switches the example grid layout app to render embeddables as panels rather than the simplified mock panel we were using previously. In doing so, I had to add the ability for custom panels to add a custom drag handle via the `renderPanelContents` callback - this required adding a `setDragHandles` callback to the `ReactEmbeddableRenderer` that could be passed down to the `PresentationPanel` component. https://github.com/user-attachments/assets/9e2c68f9-34af-4360-a978-9113701a5ea2 #### New scroll behaviour In https://github.com/elastic/kibana/pull/201867, I introduced a small "ease" to the auto-scroll effect that happens when you drag a panel to the top or bottom of the window. However, in that PR, I was using the `smooth` scrolling behaviour, which unfortunately became **very** jittery once I switched to embeddables rather than simple panels (specifically in Chrome - it worked fine in Firefox). The only way to prevent this jittery scroll was to switch to the default scroll behaviour, but this lead to a very **abrupt** stop when the scrollbar reached the top and/or bottom of the page - so, to give the same "gentle" stop that the `smooth` scroll had, I decided to recreate this effect by adding a slow down "ease" when close to the top or bottom of the page: https://github.com/user-attachments/assets/cb7bf03f-4a9e-4446-be4f-8f54c0bc88ac This effect is accomplished via the parabola formula `y = a(x-h)2 + k` and can be roughly visualized with the following, which shows that the "speed up" ease happens at a much slower pace than the "slow down" ease:  #### Notes about parent changes As I investigated improving the efficiency of the grid layout with embeddables, one of the main things I noticed was that the grid panel was **always** remounted when moving a panel from one collapsible section to another. This lead me (and @ThomThomson) down a rabbit hole of React-reparenting, and we explored a few different options to see if we could change the parent of a component **without** having it remount. In summary, after various experiments and a whole bunch of research, we determined that, due to the reconciliation of the React tree, this is unfortunately impossible. So our priorities will instead have to move to making the remount of `ReactEmbeddableRenderer` **as efficient as possible** via caching, since the remount is inevitable. ### Checklist - [x] The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) ### Identify risks There are no risks to this PR, since the most significant work is contained in the `examples` plugin. Some changes were made to the presentation panel to allow for custom drag handles, but this isn't actually used in Dashboard - so for now, this code is only called in the example plugin, as well. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> |
||
|
d92aa91c3a
|
[Dashboard][Collapsable Panels] Responsive layout (#200771)
## Summary Fixes https://github.com/elastic/kibana/issues/197714 ### Key Features #### Responsiveness 1. Adds a responsive view controlled by the `accessMode` prop. 2. For the responsive version (in the `VIEW` mode), panels retain height and are arranged based on screen order (left-to-right, top-to-bottom). 3. Interactivity (drag/resize) is disabled in `view` mode. <img width="514" alt="Screenshot 2024-11-25 at 17 34 56" src="https://github.com/user-attachments/assets/6a5a97aa-de9b-495a-b1de-301bc935a5ab"> #### Maximization 1. Supports expanded panel view using the `expandedPanelId` prop. 2. Interactivity (drag/resize) is disabled when a panel is expanded. <img width="1254" alt="Screenshot 2024-11-25 at 17 35 05" src="https://github.com/user-attachments/assets/c83014f6-18ad-435b-a59d-1d3ba3f80d84"> #### Considerations 1. CSS elements naming convention: Main component uses `kbnGrid` class, with modifiers like `kbnGrid--nonInteractive`. For the drag handle of `GridPanel` I used `kbnGridPanel__dragHandle` classname. 2. Classes vs. Inline Styles: I opted for using `kbnGrid--nonInteractive` instead of adding one more subscription to `GridPanel` to modify the styles inline. It's the first time in this package that I used classes instead of inline styles for no-initial styles setting. 3. Naming Convention: I opted for using the `expanded` word to describe an expanded panel. Another one could be `maximized` as it's more used in UI, but less in the legacy code. 4. Interactivity (drag/resize) is disabled in responsive mode but we could consider to limit this to small viewports only (<768px). --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> |
||
|
549532240c
|
[Dashboard] [Collapsable Panels] Switch to using props (#200793)
Closes https://github.com/elastic/kibana/issues/200090 ## Summary This PR migrates the `GridLayout` component a more traditional React design using **props** rather than providing an API. This change serves two purposes: 1. It makes the eventual Dashboard migration easier, since it is more similar to `react-grid-layout`'s implementation 3. It makes the `GridLayout` component less opinionated by moving the logic for panel management (i.e. panel placement, etc) to the parent component. I tried to keep efficiency in mind for this comparison, and ensured that we are still keeping the number of rerenders **o a minimum**. This PR should not introduce **any** extra renders in comparison to the API version. ### Checklist - [x] The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) ### Identify risks There are no risks to this PR, since all work is contained in the `examples` plugin. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> |
||
|
a91427d71b
|
[Dashboard] [Collapsable Panels] Add panel management API (#195513)
Closes https://github.com/elastic/kibana/issues/190445 ## Summary This PR adds the first steps of a panel management API to the `GridLayout` component: - A method to delete a panel - A method to replace a panel - A method to add a panel with a given size and placement technique (`'placeAtTop' | 'findTopLeftMostOpenSpace'`) - Currently, we only support adding a panel to the first row, since this is all that is necessary for parity with the current Dashboard layout engine - we can revisit this decision as part of the [row API](https://github.com/elastic/kibana/issues/195807). - A method to get panel count - This might not be necessary for the dashboard (we'll see), but I needed it for the example plugin to be able to generate suggested panel IDs. It's possible this will get removed 🤷 - The ability to serialize the grid layout state I only included the bare minimum here that I know will be necessary for a dashboard integration, but it's possible I missed some things and so this API will most likely expand in the future. https://github.com/user-attachments/assets/28df844c-5c12-40fd-b4f4-8fbd1a8abc20 ### Serialization With respect to serialization, there are still some open questions about how we want to handle it from the Dashboard side - therefore, in this PR, I opted to keep the serialization as simple as possible (i.e. both the input and serialized output take identical forms for the `GridLayout` component). Our goal is to keep `kbn-grid-layout` as **generic** as possible so, while I considered making the serialize method return the form that the Dashboard expects, I ultimately decided against that; instead, I think Dashboard should be responsible for taking the grid layout's serialized form and turning it into a dashboard-specific serialization of a grid layout and vice-versa for deserializing and sending the initial layout to the `GridLayout` component. The dashboard grid layout serialization will be tackled as part of https://github.com/elastic/kibana/issues/190446, where it's possible my opinion might change :) This is just a first draft of the `kbn-grid-layout` API, after all. ### Example Grid Layout In the grid layout example plugin, I integrated the API by adding some pretty bare-bones buttons to each panel in order to ensure the API works as expected - that being said, I didn't worry too much about the design of these things and so it looks pretty ugly 😆 My next step is https://github.com/elastic/kibana/issues/190379, where I will have to integrate the grid layout API with the embeddable actions, at which point the design will be improved - so this is a very temporary state 🙇 ### Checklist - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [x] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> |
||
|
b6287708f6
|
Adds AGPL 3.0 license (#192025)
Updates files outside of x-pack to be triple-licensed under Elastic License 2.0, AGPL 3.0, or SSPL 1.0. |
||
|
b02f6dbcc5
|
[Collapsable Panels] Better Scrolling for kbn grid layout (#191120)
changes `kbn grid layout` to allow better scrolling behaviour. |
||
|
7290824e74
|
[Dashboard] New layout engine (#174132)
Introduces a new performant and simple drag & drop layout engine for Kibana which uses HTML5 and CSS and and has **no external dependencies**. |