kibana/packages
Hannah Mudge 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:


![image](https://github.com/user-attachments/assets/94fbb8f6-b6b8-4f9e-af91-0128717cdffc)

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:
  
![Dec-16-2024
17-04-58](https://github.com/user-attachments/assets/9a920046-cf53-4dff-bfbe-6ed0aed05f77)

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:

   

![image](https://github.com/user-attachments/assets/47aa981e-9e4f-4c30-8570-abf6ba4a20ba)

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:


![image](https://github.com/user-attachments/assets/4c5e3aca-399c-4075-9897-a5d2d73e9284)

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:

![Dec-16-2024
17-30-28](https://github.com/user-attachments/assets/4cd7d49d-138b-4b59-ac78-0ea2cbc86c3c)

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:


![image](https://github.com/user-attachments/assets/ca82ca05-673e-4bf1-b22f-e2aa1c7b6ba4)


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:


![image](https://github.com/user-attachments/assets/ec7c08a5-d0e9-46f7-bf3c-2eede7cef6fd)

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` |
|--------|--------|
|
![image](https://github.com/user-attachments/assets/7fa1e9bb-e3dd-4f99-b011-0a46e53f0e88)
|
![image](https://github.com/user-attachments/assets/05e86a48-769d-4bae-ba48-d2fb3bdde90e)
|

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` |
|--------|--------| 
|
![image](https://github.com/user-attachments/assets/5e39a616-aa96-43be-a316-cb8fc4258b88)
|
![image](https://github.com/user-attachments/assets/520ab5b6-7049-4028-9d8c-63972aff9e92)
|


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` |
|--------|--------| 
|
![image](https://github.com/user-attachments/assets/4d6b15c6-181a-4ea0-a179-09702b50411a)
|
![image](https://github.com/user-attachments/assets/363ef360-3c4f-4327-8031-18aca3833bce)
|

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:
 
![Dec-16-2024
15-31-22](https://github.com/user-attachments/assets/29364168-6bd5-4b62-839e-a63636af71f5)

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:

![Dec-16-2024
15-12-22](https://github.com/user-attachments/assets/34f23bfd-6a5d-4ff5-8421-10b7bab89551)

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:

![Dec-16-2024
16-29-12](https://github.com/user-attachments/assets/950cb573-0caf-4c44-8f63-2fc465c2c497)
   
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:
  
![Dec-16-2024
10-17-21](https://github.com/user-attachments/assets/8157dabd-bb52-4089-9493-74cbdcf49e5e)
 
  
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:


![Dec-16-2024
17-30-28](https://github.com/user-attachments/assets/60cf3347-707c-4bc2-99e5-0e042c4cbed3)

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:


![image](https://github.com/user-attachments/assets/47ee1f8c-5107-41eb-8309-527e6fd773be)

|   | 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:
   

![image](https://github.com/user-attachments/assets/b5697592-cb0e-4fac-90c9-6f3ade5e9db9)

|   | 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:


![image](https://github.com/user-attachments/assets/e59de766-a547-499a-a181-7841179032c0)
   
|   | 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!
    

![image](https://github.com/user-attachments/assets/71869176-473f-4a48-8d0f-863b855628c4)

|   | 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>
2025-01-02 16:04:20 -07:00
..
analytics/utils/analytics_collection_utils Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
cloud Preparation for High Contrast Mode, Core/SharedUX domains (#202606) 2024-12-05 08:26:41 -07:00
content-management Gracefully disable favorites if profile is not available (#204397) 2024-12-30 16:35:51 +01:00
core use info notice for color mode change notification toast (#205364) 2025-01-02 06:01:17 -06:00
deeplinks/shared Sustainable Kibana Architecture: Move modules owned by @elastic/kibana-data-discovery (#203152) 2024-12-30 13:23:47 +01:00
home Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-ambient-common-types Adds AGPL 3.0 license (#192025) 2024-09-06 19:02:41 -06:00
kbn-ambient-ftr-types Adds AGPL 3.0 license (#192025) 2024-09-06 19:02:41 -06:00
kbn-ambient-storybook-types Adds AGPL 3.0 license (#192025) 2024-09-06 19:02:41 -06:00
kbn-ambient-ui-types Adds AGPL 3.0 license (#192025) 2024-09-06 19:02:41 -06:00
kbn-analytics Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-apm-config-loader Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-apm-synthtrace [ObsUX][Synthtrace] Remove pidusage for logging cpu usage (#204043) 2024-12-13 17:58:49 +01:00
kbn-apm-synthtrace-client [Dataset Quality] Fix failing es-promotion test on 8.x (#205188) 2024-12-30 12:46:49 +01:00
kbn-axe-config Adds AGPL 3.0 license (#192025) 2024-09-06 19:02:41 -06:00
kbn-babel-preset Sustainable Kibana Architecture: Move modules owned by @elastic/observability-ui (#202834) 2024-12-25 15:14:06 -06:00
kbn-babel-register Sustainable Kibana Architecture: Move modules owned by @elastic/kibana-operations (#202739) 2024-12-31 13:47:59 +01:00
kbn-babel-transform Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-bazel-runner Adds AGPL 3.0 license (#192025) 2024-09-06 19:02:41 -06:00
kbn-calculate-auto Adds AGPL 3.0 license (#192025) 2024-09-06 19:02:41 -06:00
kbn-calculate-width-from-char-count [deps] Replace faker with @faker-js (#201105) 2024-12-03 18:17:49 +01:00
kbn-capture-oas-snapshot-cli Adds AGPL 3.0 license (#192025) 2024-09-06 19:02:41 -06:00
kbn-chart-icons Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-charts-theme Update dependency @elastic/charts to v68.0.4 (main) (#203955) 2024-12-19 18:34:50 +01:00
kbn-check-mappings-update-cli [Security Solution] [Cases] Introduce case observables (phase 0 & 1) (#190237) 2024-12-23 14:25:58 +01:00
kbn-check-prod-native-modules-cli Adds AGPL 3.0 license (#192025) 2024-09-06 19:02:41 -06:00
kbn-ci-stats-core Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-ci-stats-performance-metrics Adds AGPL 3.0 license (#192025) 2024-09-06 19:02:41 -06:00
kbn-ci-stats-reporter Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-ci-stats-shipper-cli Adds AGPL 3.0 license (#192025) 2024-09-06 19:02:41 -06:00
kbn-cli-dev-mode Sustainable Kibana Architecture: Move modules owned by @elastic/kibana-presentation (#204843) 2024-12-23 12:32:11 -06:00
kbn-code-owners Fix CODEOWNERS (#205302) 2025-01-02 08:36:55 -06:00
kbn-coloring [Visual Refresh] Borealis visualization palettes (#201015) 2024-12-11 14:58:56 -06:00
kbn-config [Config Service] Use stripUnknownKeys when checking enabled flags (#201579) 2024-12-02 10:30:09 -06:00
kbn-config-mocks Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-config-schema [Config Service] Use stripUnknownKeys when checking enabled flags (#201579) 2024-12-02 10:30:09 -06:00
kbn-crypto Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-crypto-browser Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-cypress-config Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-data-service Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-dependency-ownership Dependency Ownership CLI (#201773) 2024-11-29 17:18:36 +01:00
kbn-dependency-usage Sustainable Kibana Architecture: Move modules owned by @elastic/security-solution (#202851) 2024-12-16 22:55:27 -06:00
kbn-dev-cli-errors Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-dev-cli-runner Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-dev-proc-runner Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-dev-utils Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-docs-utils Sustainable Kibana Architecture: Move modules owned by @elastic/kibana-presentation (#204843) 2024-12-23 12:32:11 -06:00
kbn-dom-drag-drop [deps] Replace faker with @faker-js (#201105) 2024-12-03 18:17:49 +01:00
kbn-ebt-tools Sustainable Kibana Architecture: Move modules owned by @elastic/obs-ux-logs-team (#202831) 2024-12-19 16:20:53 -06:00
kbn-es fix(tests, interactive setup): switch interactive setup tests config to non-deprecated secure_password setting (#205208) 2024-12-27 17:51:43 +01:00
kbn-es-archiver [ES body removal] @elastic/appex-qa (#204878) 2024-12-19 12:06:42 +01:00
kbn-es-errors Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-es-types [RCA] AI-assisted root cause analysis (#197200) 2024-12-11 12:35:01 +01:00
kbn-eslint-config ES Lint rules for css-in-js declarations within Kibana (#200703) 2024-12-16 15:56:52 +00:00
kbn-eslint-plugin-css Resolve false positives with eslint no color rule (#204848) 2024-12-19 10:26:48 +00:00
kbn-eslint-plugin-disable Add ESLINT constraints to detect inter-group dependencies (#194810) 2024-10-22 06:34:19 -05:00
kbn-eslint-plugin-eslint [Authz] Added section for migration routes created by utility function (#198401) 2024-10-30 13:05:38 -05:00
kbn-eslint-plugin-i18n Sustainable Kibana Architecture: Move modules owned by @elastic/obs-ux-infra_services-team (#202830) 2024-12-29 09:58:37 +01:00
kbn-eslint-plugin-imports Sustainable Kibana Architecture: Move modules owned by @elastic/kibana-operations (#202739) 2024-12-31 13:47:59 +01:00
kbn-eslint-plugin-telemetry Sustainable Kibana Architecture: Move modules owned by @elastic/obs-ux-infra_services-team (#202830) 2024-12-29 09:58:37 +01:00
kbn-event-annotation-common Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-event-annotation-components [Visual Refresh] Borealis visualization palettes (#201015) 2024-12-11 14:58:56 -06:00
kbn-expect Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-failed-test-reporter-cli [Ownership] Add code owner to ftr failure report (#203076) 2024-12-16 17:05:20 +00:00
kbn-find-used-node-modules Adds AGPL 3.0 license (#192025) 2024-09-06 19:02:41 -06:00
kbn-formatters Adds AGPL 3.0 license (#192025) 2024-09-06 19:02:41 -06:00
kbn-ftr-common-functional-services Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-ftr-common-functional-ui-services [Data Usage] functional tests (#203166) 2024-12-12 08:08:08 -05:00
kbn-ftr-screenshot-filename Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-gen-ai-functional-testing Add base FTR test coverage for inference APIs (#198000) 2024-12-04 06:39:45 -06:00
kbn-generate Code owners - sort generated entries (#198901) 2024-11-06 13:38:31 +01:00
kbn-generate-console-definitions kibana-management team module move (#203883) 2024-12-13 12:29:30 -06:00
kbn-generate-csv Update dependency @elastic/elasticsearch to ^8.16.0 (main) (#200275) 2024-12-13 02:47:34 -06:00
kbn-get-repo-files Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-grid-layout [Dashboard][Collapsable Panels] New collision resolution algorithm (#204134) 2025-01-02 16:04:20 -07:00
kbn-guided-onboarding Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-handlebars Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-hapi-mocks Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-health-gateway-server Removed TLSv1.1 from default set of supported protocols (#203856) 2024-12-16 16:27:44 +01:00
kbn-i18n Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-i18n-react Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-import-locator Adds AGPL 3.0 license (#192025) 2024-09-06 19:02:41 -06:00
kbn-import-resolver Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-interpreter Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-io-ts-utils [Perfomance] Track time range picker with onPageReady function (#202889) 2024-12-13 07:11:44 -06:00
kbn-item-buffer Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-jest-serializers Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-journeys Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-json-ast Adds AGPL 3.0 license (#192025) 2024-09-06 19:02:41 -06:00
kbn-kibana-manifest-schema Kibana Sustainable Architecture: Force visibility: 'private' for solutions in manifest (#199452) 2024-11-08 15:36:07 +01:00
kbn-lens-formula-docs Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-lint-packages-cli [codeowners] Filter kibanamachine (#199404) 2024-11-12 12:39:17 -06:00
kbn-lint-ts-projects-cli Adds AGPL 3.0 license (#192025) 2024-09-06 19:02:41 -06:00
kbn-logging Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-logging-mocks Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-managed-content-badge Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-managed-vscode-config Adds AGPL 3.0 license (#192025) 2024-09-06 19:02:41 -06:00
kbn-managed-vscode-config-cli Adds AGPL 3.0 license (#192025) 2024-09-06 19:02:41 -06:00
kbn-management Fix storybook for kibana management (#205299) 2025-01-02 07:24:08 -06:00
kbn-manifest Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-mock-idp-plugin Preparation for High Contrast Mode, Security domains (#202609) 2024-12-09 13:03:23 -07:00
kbn-mock-idp-utils Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-monaco Sustainable Kibana Architecture: Move modules owned by @elastic/kibana-operations (#202739) 2024-12-31 13:47:59 +01:00
kbn-object-versioning Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-object-versioning-utils Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-openapi-bundler Updated js-yaml to v4 (#190678) 2024-09-19 12:25:03 +02:00
kbn-openapi-generator Sustainable Kibana Architecture: Move modules owned by @elastic/security-solution (#202851) 2024-12-16 22:55:27 -06:00
kbn-optimizer Remove bfetch plugin (#204285) 2024-12-19 14:51:58 -07:00
kbn-optimizer-webpack-helpers Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-palettes [Visual Refresh] Borealis visualization palettes (#201015) 2024-12-11 14:58:56 -06:00
kbn-peggy Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-peggy-loader Adds AGPL 3.0 license (#192025) 2024-09-06 19:02:41 -06:00
kbn-performance-testing-dataset-extractor [ES body removal] @elastic/appex-qa (#204878) 2024-12-19 12:06:42 +01:00
kbn-picomatcher Adds AGPL 3.0 license (#192025) 2024-09-06 19:02:41 -06:00
kbn-plugin-check Adds AGPL 3.0 license (#192025) 2024-09-06 19:02:41 -06:00
kbn-plugin-generator Sustainable Kibana Architecture: Update tooling to take into account the new folders (#202327) 2024-12-02 04:04:35 -06:00
kbn-plugin-helpers Sustainable Kibana Architecture: Move modules owned by @elastic/kibana-operations (#202739) 2024-12-31 13:47:59 +01:00
kbn-react-mute-legacy-root-warning [SKA] Categorize outstanding shared-ux modules (#205378) 2025-01-02 08:14:22 -06:00
kbn-recently-accessed Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-relocate SKA: Relocate script V6.2 (#205244) 2024-12-30 14:25:16 +01:00
kbn-repo-file-maps Adds AGPL 3.0 license (#192025) 2024-09-06 19:02:41 -06:00
kbn-repo-linter Adds AGPL 3.0 license (#192025) 2024-09-06 19:02:41 -06:00
kbn-repo-path Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-repo-source-classifier Sustainable Kibana Architecture: Fix group inference logic: add missing packages folders (#201758) 2024-11-26 11:42:17 -06:00
kbn-repo-source-classifier-cli Adds AGPL 3.0 license (#192025) 2024-09-06 19:02:41 -06:00
kbn-reporting Preparation for High Contrast Mode, Core/SharedUX domains (#202606) 2024-12-05 08:26:41 -07:00
kbn-router-to-openapispec [OAS] Remove Elastic-Api-Version (#202923) 2024-12-05 17:05:42 +01:00
kbn-safer-lodash-set Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-saved-objects-settings Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-saved-search-component [Discover] Rename Saved Search to Discover Session (#202217) 2024-12-18 13:45:32 +01:00
kbn-scout [scout] adding unit tests (#204567) 2024-12-19 17:36:07 +01:00
kbn-scout-info [kbn-scout] Custom event-oriented test reporter & persistence (#202906) 2024-12-09 14:34:25 +00:00
kbn-scout-reporting [kbn-code-owners] General improvements (#204023) 2024-12-12 12:05:01 -06:00
kbn-screenshotting-server Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-security-hardening Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-server-http-tools Removed TLSv1.1 from default set of supported protocols (#203856) 2024-12-16 16:27:44 +01:00
kbn-set-map Adds AGPL 3.0 license (#192025) 2024-09-06 19:02:41 -06:00
kbn-shared-ux-utility Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-some-dev-log Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-sort-package-json Adds AGPL 3.0 license (#192025) 2024-09-06 19:02:41 -06:00
kbn-sort-predicates Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-std Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-stdio-dev-helpers Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-storybook Fixes for storybook aliases (#204842) 2024-12-26 08:38:22 -08:00
kbn-telemetry-tools [Sustainable Architecture] Telemetry schemas (#201760) 2024-11-27 18:18:09 +01:00
kbn-test [ftr] Speed up FTR code owner check (#205093) 2025-01-02 11:10:20 -06:00
kbn-test-eui-helpers Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-test-jest-helpers Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-test-subj-selector [scout] migrate more Discover tests (#201842) 2024-12-02 20:57:29 +01:00
kbn-timelion-grammar Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-tinymath Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-tooling-log Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-transpose-utils Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-ts-projects Dependency usage CLI (#198920) 2024-11-25 14:07:40 +01:00
kbn-ts-type-check-cli Remove references to old type check script (#202825) 2024-12-18 11:38:30 -08:00
kbn-ui-actions-browser Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
kbn-use-tracked-promise Adds AGPL 3.0 license (#192025) 2024-09-06 19:02:41 -06:00
kbn-user-profile-components [Theme] configure appearance color mode (#203406) 2024-12-30 09:43:48 +00:00
kbn-utility-types [Streams] App plugin (#200060) 2024-11-25 14:51:24 +01:00
kbn-validate-next-docs-cli Adds AGPL 3.0 license (#192025) 2024-09-06 19:02:41 -06:00
kbn-visualization-ui-components [Visual Refresh] Borealis visualization palettes (#201015) 2024-12-11 14:58:56 -06:00
kbn-visualization-utils [React18] Migrate test suites to account for testing library upgrades kibana-visualizations (#201152) 2024-11-22 16:34:11 +01:00
kbn-web-worker-stub Adds AGPL 3.0 license (#192025) 2024-09-06 19:02:41 -06:00
kbn-whereis-pkg-cli Adds AGPL 3.0 license (#192025) 2024-09-06 19:02:41 -06:00
kbn-yarn-lock-validator Adds AGPL 3.0 license (#192025) 2024-09-06 19:02:41 -06:00
kbn-zod Sustainable Kibana Architecture: Categorise straightforward packages (#199630) 2024-11-22 10:33:25 +01:00
react Add @kbn/react-kibana-context-* packages to shared bundle (#204794) 2024-12-30 11:33:20 +01:00
response-ops Sustainable Kibana Architecture: Move modules owned by @elastic/response-ops (#202836) 2024-12-26 15:49:50 +01:00
serverless Sustainable Kibana Architecture: Move modules owned by @elastic/search-kibana (#202837) 2024-12-27 10:55:21 -06:00
shared-ux [SKA] Categorize outstanding shared-ux modules (#205378) 2025-01-02 08:14:22 -06:00
README.md

Kibana-related packages

This folder contains packages that are intended for use in Kibana and Kibana plugins.

tl;dr:

  • Don't publish to npm registry
  • Always use the @kbn namespace
  • Always set "private": true in package.json

Using these packages

We no longer publish these packages to the npm registry. Now, instead of specifying a version when including these packages, we rely on yarn workspaces, which sets up a symlink to the package.

For example if you want to use the @kbn/i18n package in Kibana itself, you can specify the dependency like this:

"@kbn/i18n": "1.0.0"

However, if you want to use this from a Kibana plugin, you need to use a link: dependency and account for the relative location of the Kibana repo, so it would instead be:

"@kbn/i18n": "link:../../kibana/packages/kbn-i18n"

then run yarn kbn bootstrap from the plugin directory.

Creating a new package

Run the following command from the root of the Kibana repo:

node scripts/generate package @kbn/<PACKAGE_NAME> --web --owner @elastic/<TEAM_NAME>

Unit tests for a package

Currently there is only one tool being used in order to test packages which is Jest. Below we will explain how it should be done.

Jest

A package should follow the pattern of having .test.js files as siblings of the source code files, and these run by Jest.

A package using the .test.js naming convention will have those tests automatically picked up by Jest and run by the unit test runner, currently mapped to the Kibana test script in the root package.json.

  • yarn test runs all unit tests.
  • yarn jest runs all Jest tests in Kibana.

In order for the plugin or package to use Jest, a jest.config.js file must be present in it's root. However, there are safeguards for this in CI should a test file be added without a corresponding config file.


Each package can also specify its own test script in the package's package.json, for cases where you'd prefer to run the tests from the local package directory.