Skip to content

Commit aaaf92e

Browse files
camdArchaeopteryx
andauthored
fix: React Bootstrap un-revert with fixups (#8996)
* Reapply "migrate reactstrap to react bootstrap (#8897)" because of rendering issues with dropdowns and bugfiler (#8988) This reverts commit b1faecc. * fix: Dropdowns for elipsis and CustomMenuActions dropdowns * fix: Bugfiler and tier toggles * fix Bootstrap bugs * fixes for dropdowns * intermittent failure view fixes * fixes to perfherder and links * fix several UI differences for bootstrap * fix colors and fast next navigation * more cleanup fixes * fix details panel with pinboard resizing * fix bugfiler * perfherder fixes * Bug 2000886: fixed - fuzzy jobs * fix bug 2000874 * fix bug 2000869 * fix bug 2000854 * fix remove bug vertical spacing * fix bug 2000847 * fix bug 2000804 * fix bug 2000627 * Fix casing of CSS variable for outline of selected job * Bug 2000632 - show outline for selected job --------- Co-authored-by: Sebastian Hengst <aryx.github@gmx-topmail.de>
1 parent 6d5c7c2 commit aaaf92e

File tree

167 files changed

+4395
-3292
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

167 files changed

+4395
-3292
lines changed

docs/accessibility.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ For example:
5454
</Button>
5555
```
5656

57-
Known reactstrap components that accept the `color` prop and work with custom Treeherder colors: `Badge`, `Button`, `Card`, `DropdownToggle`, `FormText`, `NavBar`, `Progress`, `Spinner`.
57+
Known reactstrap components that accept the `color` prop and work with custom Treeherder colors: `Badge`, `Button`, `Card`, `Dropdown.Toggle`, `FormText`, `NavBar`, `Progress`, `Spinner`.
5858

5959
In case you need to add more custom colors, please add on [treeherder-custom-styles.css](https://github.com/mozilla/treeherder/blob/master/ui/css/treeherder-custom-styles.css#L348) style sheet.
6060

@@ -102,7 +102,7 @@ If your case is more specific, please check [this guide](https://css-tricks.com/
102102

103103
## Interactive elements
104104

105-
When creating elements that have event listeners, prefer any component of the reactstrap interactive elements. Examples are: `Button`, `Input`, `DropdownToggle`. You can also choose a HTML `<a>` element.
105+
When creating elements that have event listeners, prefer any component of the reactstrap interactive elements. Examples are: `Button`, `Input`, `Dropdown.Toggle`. You can also choose a HTML `<a>` element.
106106

107107
If you need to insert an event listener in a non-interactive element, such as a `span`, add also an `aria-role` of `button`, `link`, `checkbox`, or whatever seems closer to the functionality of the element.
108108

@@ -116,10 +116,10 @@ If you need to insert an event listener in a non-interactive element, such as a
116116

117117
There is a special case when you are creating a dropdown menu. First of all, try to follow [reactstrap structure](https://reactstrap.github.io/components/dropdowns/).
118118

119-
Lastly, insert an additional tag `prop` to `DropdownItem` component.
119+
Lastly, insert an additional tag `prop` to `Dropdown.Item` component.
120120

121121
```jsx
122-
<DropdownItem tag="a"> Menu Item </DropdownItem>
122+
<Dropdown.Item tag="a"> Menu Item </Dropdown.Item>
123123
```
124124

125125
## Forms, inputs and buttons

package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"@fortawesome/react-fontawesome": "0.2.6",
1919
"@mui/material": "7.1.2",
2020
"@mui/styled-engine-sc": "npm:@mui/styled-engine-sc@latest",
21+
"@popperjs/core": "2.11.8",
2122
"@types/react": "*",
2223
"@types/react-dom": "*",
2324
"ajv": "8.17.1",
@@ -42,6 +43,7 @@
4243
"prop-types": "15.8.1",
4344
"query-string": "7.0.1",
4445
"react": "18.3.1",
46+
"react-bootstrap": "2.10.10",
4547
"react-dates": "21.8.0",
4648
"react-dom": "18.3.1",
4749
"react-helmet": "6.1.0",
@@ -55,7 +57,6 @@
5557
"react-split-pane": "0.1.92",
5658
"react-table-6": "6.11.0",
5759
"react-tabs": "6.1.0",
58-
"reactstrap": "8.10.1",
5960
"redoc": "2.4.0",
6061
"redux": "4.2.1",
6162
"redux-debounce": "1.0.1",
@@ -87,6 +88,7 @@
8788
"@testing-library/react": "16.2.0",
8889
"babel-jest": "29.7.0",
8990
"babel-loader": "10.0.0",
91+
"bootstrap": "5.3.8",
9092
"clean-webpack-plugin": "4.0.0",
9193
"copy-webpack-plugin": "13.0.1",
9294
"css-loader": "7.1.2",
@@ -111,6 +113,8 @@
111113
"path": "0.12.7",
112114
"prettier": "2.2.1",
113115
"puppeteer": "24.2.1",
116+
"sass": "1.93.2",
117+
"sass-loader": "16.0.6",
114118
"setup-polly-jest": "0.11.0",
115119
"style-loader": "4.0.0",
116120
"webpack": "5.97.1",

tests/ui/job-view/App_test.jsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ describe('App', () => {
7878
[],
7979
);
8080
fetchMock.get(getProjectUrl('/jobs/259537375/', repoName), fullJob);
81+
fetchMock.get(
82+
getProjectUrl('/jobs/259537375/bug_suggestions/', repoName),
83+
[],
84+
);
8185
fetchMock.get(getProjectUrl('/jobs/259537372/', repoName), {
8286
...fullJob,
8387
task_id: 'secondTaskId',

tests/ui/job-view/Filtering_test.jsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,11 @@ describe('Filtering', () => {
198198
);
199199
expect(unfilteredPushes).toHaveLength(10);
200200

201+
// Open the filters dropdown to reveal menu items
202+
const filtersDropdown = await waitFor(() => getByTitle('Set filters'));
203+
fireEvent.click(filtersDropdown);
204+
205+
// Wait for dropdown to open and find "My pushes only"
201206
const myPushes = await waitFor(() => getByText('My pushes only'));
202207
fireEvent.click(myPushes);
203208

@@ -368,8 +373,15 @@ describe('Filtering', () => {
368373
});
369374

370375
describe('by result status', () => {
376+
const statusMap = {
377+
green: 'success',
378+
red: 'failures',
379+
dkgray: 'in progress',
380+
};
381+
371382
const clickFilterChicklet = (color) => {
372-
fireEvent.click(document.querySelector(`.btn-${color}-filter-chicklet`));
383+
const status = statusMap[color];
384+
fireEvent.click(document.querySelector(`[data-status="${status}"]`));
373385
};
374386

375387
test('uncheck success should leave 30 jobs', async () => {

tests/ui/job-view/bugfiler_test.jsx

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,45 +26,85 @@ describe('BugFiler', () => {
2626
const suggestions = [
2727
{
2828
search: 'ShutdownLeaks | process() called before end of test suite',
29+
bugs: { open_recent: [], all_others: [] },
30+
counter: 1,
31+
failure_in_new_rev: false,
32+
line_number: 1,
33+
path_end: null,
34+
search_terms: [],
2935
},
3036
{
3137
search:
3238
'browser/components/search/test/browser_searchbar_smallpanel_keyboard_navigation.js | application terminated with exit code 11',
39+
bugs: { open_recent: [], all_others: [] },
40+
counter: 1,
41+
failure_in_new_rev: false,
42+
line_number: 2,
43+
path_end:
44+
'browser/components/search/test/browser_searchbar_smallpanel_keyboard_navigation.js',
45+
search_terms: [],
3346
},
3447
{
3548
search:
3649
'browser/components/search/test/browser_searchbar_smallpanel_keyboard_navigation.js | application crashed [@ js::GCMarker::eagerlyMarkChildren]',
50+
bugs: { open_recent: [], all_others: [] },
51+
counter: 1,
52+
failure_in_new_rev: false,
53+
line_number: 3,
54+
path_end:
55+
'browser/components/search/test/browser_searchbar_smallpanel_keyboard_navigation.js',
56+
search_terms: [],
3757
},
3858
{
3959
search:
4060
'leakcheck | default process: missing output line for total leaks!',
61+
bugs: { open_recent: [], all_others: [] },
62+
counter: 1,
63+
failure_in_new_rev: false,
64+
line_number: 4,
65+
path_end: null,
66+
search_terms: [],
67+
},
68+
{
69+
search: '# TBPL FAILURE #',
70+
bugs: { open_recent: [], all_others: [] },
71+
counter: 1,
72+
failure_in_new_rev: false,
73+
line_number: 5,
74+
path_end: null,
75+
search_terms: [],
4176
},
42-
{ search: '# TBPL FAILURE #' },
4377
];
4478

4579
const PdfSuggestions = [
4680
{
47-
bugs: {},
81+
bugs: { open_recent: [], all_others: [] },
4882
line_number: 10,
4983
path_end: 'browser/extensions/pdfjs/test/browser_pdfjs_views.js',
5084
search_terms: [],
5185
search:
5286
'TEST-UNEXPECTED-FAIL | browser/extensions/pdfjs/test/browser_pdfjs_views.js | Test timed out -',
87+
counter: 1,
88+
failure_in_new_rev: false,
5389
},
5490
{
55-
bugs: {},
91+
bugs: { open_recent: [], all_others: [] },
5692
line_number: 235,
5793
path_end: 'browser/extensions/pdfjs/test/browser_pdfjs_views.js',
5894
search_terms: [],
5995
search:
6096
'TEST-UNEXPECTED-FAIL | browser/extensions/pdfjs/test/browser_pdfjs_views.js | Found a tab after previous test timed out: about:blank -',
97+
counter: 1,
98+
failure_in_new_rev: false,
6199
},
62100
{
63-
bugs: {},
101+
bugs: { open_recent: [], all_others: [] },
64102
line_number: 783,
65103
path_end: 'flee',
66104
search_terms: [],
67105
search: 'REFTEST TEST-UNEXPECTED-PASS | flee | floo',
106+
counter: 1,
107+
failure_in_new_rev: false,
68108
},
69109
];
70110

@@ -82,6 +122,24 @@ describe('BugFiler', () => {
82122
},
83123
],
84124
);
125+
fetchMock.mock(
126+
`/api${bzComponentEndpoint}?path=browser%2Fcomponents%2Fsearch%2Ftest%2Fbrowser_searchbar_smallpanel_keyboard_navigation.js`,
127+
[
128+
{
129+
product: 'Firefox',
130+
component: 'Search',
131+
},
132+
],
133+
);
134+
fetchMock.mock(
135+
`/api${bzComponentEndpoint}?path=browser%2Fcomponents%2Fsessionstore%2Ftest%2Fbrowser_625016.js`,
136+
[
137+
{
138+
product: 'Firefox',
139+
component: 'Session Restore',
140+
},
141+
],
142+
);
85143

86144
fetchMock.mock(
87145
`${bzBaseUrl}rest/prod_comp_search/find/firefox%20::%20search?limit=5`,
@@ -175,6 +233,12 @@ describe('BugFiler', () => {
175233
'browser_searchbar_smallpanel_keyboard_navigation.js", "[@ js::GCMarker::eagerlyMarkChildren]',
176234
],
177235
search: summary,
236+
bugs: { open_recent: [], all_others: [] },
237+
counter: 1,
238+
failure_in_new_rev: false,
239+
line_number: 1,
240+
path_end:
241+
'browser/components/search/test/browser_searchbar_smallpanel_keyboard_navigation.js',
178242
};
179243

180244
render(bugFilerComponentSuggestion(suggestion));

tests/ui/perfherder/alerts-view/alerts_test.jsx

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -622,8 +622,20 @@ test('Selecting `all` from (frameworks|projects) dropdown shows all (frameworks|
622622
const { queryAllByText, getByTestId } = alertsView();
623623

624624
const allFromDropdown = await waitFor(() => queryAllByText(/all/));
625-
fireEvent.click(allFromDropdown[0]);
626-
fireEvent.click(allFromDropdown[1]);
625+
// Find the actual clickable parent elements (dropdown items) that contain the text "all"
626+
const clickableElements = allFromDropdown
627+
.map(
628+
(textNode) =>
629+
textNode.closest('a') ||
630+
textNode.closest('button') ||
631+
textNode.closest('[role="button"]'),
632+
)
633+
.filter(Boolean);
634+
635+
if (clickableElements.length >= 2) {
636+
fireEvent.click(clickableElements[0]);
637+
fireEvent.click(clickableElements[1]);
638+
}
627639

628640
const alert1 = await waitFor(() => getByTestId('69526'));
629641
const alert2 = await waitFor(() => getByTestId('69530'));
@@ -740,7 +752,7 @@ test(`table data cannot be sorted by 'Tags & Options'`, async () => {
740752
getAllByTitle('Sorted by tags & options disabled'),
741753
);
742754

743-
expect(sortByTags[0]).toHaveClass('disabled-button');
755+
expect(sortByTags[0]).toBeDisabled();
744756
});
745757

746758
test(`table data can be sorted in ascending order by 'Confidence'`, async () => {

tests/ui/perfherder/alerts-view/modal_perf_tags_test.jsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ test('An active/checked tag can be unchecked', async () => {
5454

5555
test('Modal closes on X', async () => {
5656
const handleClose = jest.fn();
57-
const { getByText } = testTagsModal(handleClose);
57+
const { getByLabelText } = testTagsModal(handleClose);
5858

59-
const closeButton = await waitFor(() => getByText('));
59+
const closeButton = await waitFor(() => getByLabelText('Close'));
6060

6161
expect(closeButton).toBeInTheDocument();
6262

@@ -69,7 +69,7 @@ test('Modal does not keep unsaved changes', async () => {
6969
testAlertSummary.performance_tags = ['harness'];
7070

7171
const handleClose = jest.fn();
72-
const { getByText, getByTestId } = testTagsModal(handleClose);
72+
const { getByLabelText, getByTestId } = testTagsModal(handleClose);
7373

7474
let activeTag = await waitFor(() => getByTestId('modal-perf-tag harness'));
7575

@@ -78,7 +78,7 @@ test('Modal does not keep unsaved changes', async () => {
7878
fireEvent.change(activeTag, { target: { checked: false } });
7979
expect(activeTag.checked).toBeFalsy();
8080

81-
const closeButton = await waitFor(() => getByText('));
81+
const closeButton = await waitFor(() => getByLabelText('Close'));
8282
fireEvent.click(closeButton);
8383

8484
expect(handleClose).toHaveBeenCalledTimes(1);

tests/ui/perfherder/alerts-view/select_alert_framework_test.jsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { render } from '@testing-library/react';
1+
import { render, fireEvent } from '@testing-library/react';
22
import { noop } from 'lodash';
33
import React from 'react';
44

@@ -41,10 +41,14 @@ const testFrameworksDropdown = () => {
4141
};
4242

4343
test('should pin the right number of items to top and bottom frameworks w.r.t config', async () => {
44-
testFrameworksDropdown();
44+
const { container } = testFrameworksDropdown();
4545
// top pinned represents all items in the drop down that is at the top of the list
4646
// bottom pinned represents all items in the drop down that is at the bottom of the list.
4747

48+
// Open the dropdown to render the menu items
49+
const dropdownToggle = container.querySelector('.dropdown-toggle');
50+
fireEvent.click(dropdownToggle);
51+
4852
const topPinned = document.querySelectorAll('.top-pinned');
4953
const bottomPinned = document.querySelectorAll('.bottom-pinned');
5054

tests/ui/perfherder/alerts-view/status_dropdown_test.jsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ afterEach(cleanup);
5252
test("Summary with no tags shows 'Add tags'", async () => {
5353
const { getByText } = testStatusDropdown([]);
5454

55+
// Open the status dropdown first
56+
const statusDropdown = await waitFor(() => getByText('untriaged'));
57+
fireEvent.click(statusDropdown);
58+
5559
const dropdownItem = await waitFor(() => getByText('Add tags'));
5660

5761
expect(dropdownItem).toBeInTheDocument();
@@ -60,6 +64,10 @@ test("Summary with no tags shows 'Add tags'", async () => {
6064
test("Summary with tags shows 'Edit tags'", async () => {
6165
const { getByText } = testStatusDropdown(['harness']);
6266

67+
// Open the status dropdown first
68+
const statusDropdown = await waitFor(() => getByText('untriaged'));
69+
fireEvent.click(statusDropdown);
70+
6371
const dropdownItem = await waitFor(() => getByText('Edit tags'));
6472

6573
expect(dropdownItem).toBeInTheDocument();
@@ -68,6 +76,10 @@ test("Summary with tags shows 'Edit tags'", async () => {
6876
test("Tags modal opens from 'Add tags'", async () => {
6977
const { getByText, getByTestId } = testStatusDropdown([]);
7078

79+
// Open the status dropdown first
80+
const statusDropdown = await waitFor(() => getByText('untriaged'));
81+
fireEvent.click(statusDropdown);
82+
7183
const dropdownItem = await waitFor(() => getByText('Add tags'));
7284

7385
fireEvent.click(dropdownItem);
@@ -80,6 +92,10 @@ test("Tags modal opens from 'Add tags'", async () => {
8092
test("Tags modal opens from 'Edit tags'", async () => {
8193
const { getByText, getByTestId } = testStatusDropdown(['harness']);
8294

95+
// Open the status dropdown first
96+
const statusDropdown = await waitFor(() => getByText('untriaged'));
97+
fireEvent.click(statusDropdown);
98+
8399
const dropdownItem = await waitFor(() => getByText('Edit tags'));
84100

85101
fireEvent.click(dropdownItem);

0 commit comments

Comments
 (0)