diff --git a/cypress/e2e/Incidents/incidents.spec.js b/cypress/e2e/Incidents/incidents.spec.js index ef7733e4..39029b30 100644 --- a/cypress/e2e/Incidents/incidents.spec.js +++ b/cypress/e2e/Incidents/incidents.spec.js @@ -310,9 +310,7 @@ describe('Manage Open Incidents', { failFast: { enabled: false } }, () => { removeColumns.map((column) => column[1]), ); - const addColumns = [ - ['Num Alerts', 'num_alerts'], - ]; + const addColumns = [['Num Alerts', 'num_alerts']]; manageIncidentTableColumns( 'add', addColumns.map((column) => column[1]), @@ -324,7 +322,9 @@ describe('Manage Open Incidents', { failFast: { enabled: false } }, () => { .should('be.visible') .should('contain', '1'); - cy.get(`[data-incident-header="Num Alerts"][data-incident-row-cell-idx="${incidentIdx}"]`).within(() => { + cy.get( + `[data-incident-header="Num Alerts"][data-incident-row-cell-idx="${incidentIdx}"]`, + ).within(() => { cy.get('[aria-haspopup="dialog"]').realHover(); }); @@ -340,7 +340,9 @@ describe('Manage Open Incidents', { failFast: { enabled: false } }, () => { it('Split/move alert from one incident to a new incident', () => { const incidentIdx = 0; - cy.get(`[data-incident-header="Num Alerts"][data-incident-row-cell-idx="${incidentIdx}"]`).within(() => { + cy.get( + `[data-incident-header="Num Alerts"][data-incident-row-cell-idx="${incidentIdx}"]`, + ).within(() => { cy.get('[aria-haspopup="dialog"]').click(); }); @@ -348,7 +350,9 @@ describe('Manage Open Incidents', { failFast: { enabled: false } }, () => { cy.get('#alerts-modal-move-btn').click(); cy.get('#alerts-modal-move-select').type('Move all selected alerts to one new incident{enter}'); - cy.get('#alerts-modal-move-summary-input').clear().type('New incident created from split alert'); + cy.get('#alerts-modal-move-summary-input') + .clear() + .type('New incident created from split alert'); cy.get('#alerts-modal-complete-move-btn').click(); checkActionAlertsModalContent('Alerts moved'); @@ -368,7 +372,9 @@ describe('Manage Open Incidents', { failFast: { enabled: false } }, () => { waitForIncidentTable(); const incidentIdx = 0; - cy.get(`[data-incident-header="Num Alerts"][data-incident-row-cell-idx="${incidentIdx}"]`).within(() => { + cy.get( + `[data-incident-header="Num Alerts"][data-incident-row-cell-idx="${incidentIdx}"]`, + ).within(() => { cy.get('[aria-haspopup="dialog"]').should('be.visible').should('have.text', '2').click(); }); @@ -376,7 +382,9 @@ describe('Manage Open Incidents', { failFast: { enabled: false } }, () => { selectAlert(1); cy.get('#alerts-modal-move-btn').click(); - cy.get('#alerts-modal-move-select').type('Move each selected alert to its own new incident{enter}'); + cy.get('#alerts-modal-move-select').type( + 'Move each selected alert to its own new incident{enter}', + ); cy.get('#alerts-modal-complete-move-btn').click(); checkActionAlertsModalContent('Alerts moved'); @@ -389,16 +397,20 @@ describe('Manage Open Incidents', { failFast: { enabled: false } }, () => { selectIncident(targetIncidentIdx); cy.get(`@selectedIncidentId_${targetIncidentIdx}`).then((incidentId) => { - cy.get(`[data-incident-header="Num Alerts"][data-incident-cell-id="${incidentId}"]`).within(() => { - cy.get('[aria-haspopup="dialog"]').should('be.visible').should('have.text', '1'); - }); + cy.get(`[data-incident-header="Num Alerts"][data-incident-cell-id="${incidentId}"]`).within( + () => { + cy.get('[aria-haspopup="dialog"]').should('be.visible').should('have.text', '1'); + }, + ); cy.get(`[data-incident-header="Title"][data-incident-cell-id="${incidentId}"]`).within(() => { cy.get('a').invoke('text').as('targetIncidentTitle'); }); }); - cy.get(`[data-incident-header="Num Alerts"][data-incident-row-cell-idx="${sourceIncidentIdx}"]`).within(() => { + cy.get( + `[data-incident-header="Num Alerts"][data-incident-row-cell-idx="${sourceIncidentIdx}"]`, + ).within(() => { cy.get('[aria-haspopup="dialog"]').should('be.visible').should('have.text', '1').click(); }); @@ -415,9 +427,11 @@ describe('Manage Open Incidents', { failFast: { enabled: false } }, () => { waitForIncidentTable(); cy.get(`@selectedIncidentId_${targetIncidentIdx}`).then((incidentId) => { - cy.get(`[data-incident-header="Num Alerts"][data-incident-cell-id="${incidentId}"]`).within(() => { - cy.get('[aria-haspopup="dialog"]').should('be.visible').should('have.text', '2'); - }); + cy.get(`[data-incident-header="Num Alerts"][data-incident-cell-id="${incidentId}"]`).within( + () => { + cy.get('[aria-haspopup="dialog"]').should('be.visible').should('have.text', '2'); + }, + ); }); // Tidy up by resolving the incident with two alerts diff --git a/cypress/e2e/Search/search.spec.js b/cypress/e2e/Search/search.spec.js index a52a5c4d..e3a8f180 100644 --- a/cypress/e2e/Search/search.spec.js +++ b/cypress/e2e/Search/search.spec.js @@ -70,10 +70,17 @@ describe('Search Incidents', { failFast: { enabled: false } }, () => { cy.wait(1000); cy.get('[data-incident-header="Latest Note"]').each(($el) => { // cy.wrap($el).should('have.text', 'foobar'); - cy.wrap($el).find('*').should((subElements) => { - const elementWithFoobar = subElements.toArray().find((el) => el.textContent.includes('foobar')); - assert.isNotNull(elementWithFoobar, 'Expected to find a subelement containing "foobar"'); - }); + cy.wrap($el) + .find('*') + .should((subElements) => { + const elementWithFoobar = subElements + .toArray() + .find((el) => el.textContent.includes('foobar')); + assert.isNotNull( + elementWithFoobar, + 'Expected to find a subelement containing "foobar"', + ); + }); }); }); cy.get('#global-search-input').clear(); @@ -95,10 +102,17 @@ describe('Search Incidents', { failFast: { enabled: false } }, () => { cy.get('#global-search-input').clear().type('foobaz'); cy.wait(1000); cy.get('[data-incident-header="Latest Note"]').each(($el) => { - cy.wrap($el).find('*').should((subElements) => { - const elementWithFoobar = subElements.toArray().find((el) => el.textContent.includes('foobar')); - assert.isNotNull(elementWithFoobar, 'Expected to find a subelement containing "foobar"'); - }); + cy.wrap($el) + .find('*') + .should((subElements) => { + const elementWithFoobar = subElements + .toArray() + .find((el) => el.textContent.includes('foobar')); + assert.isNotNull( + elementWithFoobar, + 'Expected to find a subelement containing "foobar"', + ); + }); }); }); cy.get('#global-search-input').clear(); diff --git a/jest.config.js b/jest.config.js index a844009b..f824c75a 100644 --- a/jest.config.js +++ b/jest.config.js @@ -14,5 +14,7 @@ module.exports = { '^.+\\.(js|jsx|ts|tsx|mjs)$': 'babel-jest', '^.+\\.svg$': 'jest-transformer-svg', }, - transformIgnorePatterns: ['/node_modules/(?!(somePkg)|react-dnd|dnd-core|@react-dnd|jsonpath-plus)'], + transformIgnorePatterns: [ + '/node_modules/(?!(somePkg)|react-dnd|dnd-core|@react-dnd|jsonpath-plus)', + ], }; diff --git a/package.json b/package.json index 60fe1443..fcefae9f 100644 --- a/package.json +++ b/package.json @@ -116,7 +116,7 @@ "dotenv": "^16.3.1", "eslint": "^8.43.0", "eslint-config-airbnb": "^18.2.1", - "eslint-config-prettier": "^8.8.0", + "eslint-config-prettier": "^9.0.0", "eslint-config-react-app": "^7.0.1", "eslint-import-resolver-alias": "^1.1.2", "eslint-plugin-cypress": "^2.14.0", @@ -138,9 +138,9 @@ "jest-environment-node": "^29.7.0", "jest-location-mock": "^1.0.10", "jest-transformer-svg": "^2.0.1", - "prettier": "^2.8.0", - "prettier-eslint": "^15.0.1", - "prettier-eslint-cli": "^7.1.0", + "prettier": "^3.1.0", + "prettier-eslint": "^16.1.2", + "prettier-eslint-cli": "^8.0.1", "redux-mock-store": "^1.5.4", "redux-saga-test-plan": "^4.0.6", "sass": "^1.66.1", diff --git a/src/App.jsx b/src/App.jsx index e63b45a5..92abc5d4 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -206,11 +206,14 @@ const App = () => { // Setup log entry clearing useEffect(() => { - const clearingInterval = setInterval(() => { - if (userAuthorized) { - cleanRecentLogEntriesAsync(); - } - }, 60 * 60 * 1000); + const clearingInterval = setInterval( + () => { + if (userAuthorized) { + cleanRecentLogEntriesAsync(); + } + }, + 60 * 60 * 1000, + ); return () => clearInterval(clearingInterval); }, [userAuthorized]); diff --git a/src/components/IncidentActions/subcomponents/PriorityMenu.jsx b/src/components/IncidentActions/subcomponents/PriorityMenu.jsx index 13a38d66..6712561d 100644 --- a/src/components/IncidentActions/subcomponents/PriorityMenu.jsx +++ b/src/components/IncidentActions/subcomponents/PriorityMenu.jsx @@ -40,11 +40,12 @@ const PriorityMenu = () => { dispatch(updatePriorityConnected(incidents, priorityId)); }; - const enabled = useMemo(() => ( - selectedRows.length > 0 - && Array.isArray(abilities) - && !abilities.includes('disable_edit_priority') - ), [selectedRows]); + const enabled = useMemo( + () => selectedRows.length > 0 + && Array.isArray(abilities) + && !abilities.includes('disable_edit_priority'), + [selectedRows], + ); return ( diff --git a/src/components/IncidentTable/IncidentTableComponent.jsx b/src/components/IncidentTable/IncidentTableComponent.jsx index fe337e57..c98595d4 100644 --- a/src/components/IncidentTable/IncidentTableComponent.jsx +++ b/src/components/IncidentTable/IncidentTableComponent.jsx @@ -21,7 +21,12 @@ import { } from 'react-window'; import { - useTable, useSortBy, useRowSelect, useBlockLayout, useResizeColumns, useFilters, + useTable, + useSortBy, + useRowSelect, + useBlockLayout, + useResizeColumns, + useFilters, } from 'react-table'; import { @@ -290,7 +295,9 @@ const IncidentTableComponent = () => { 0} + isIndeterminate={ + !tableInstance.isAllRowsSelected && tableInstance.selectedFlatRows.length > 0 + } isChecked={tableInstance.isAllRowsSelected} {...getToggleAllRowsSelectedProps()} /> @@ -380,7 +387,8 @@ const IncidentTableComponent = () => { if (inView) { if ( !row.original.alerts - || (Array.isArray(row.original.alerts) && row.original.alerts.length !== row.original.alert_counts?.all) + || (Array.isArray(row.original.alerts) + && row.original.alerts.length !== row.original.alert_counts?.all) ) { getIncidentAlerts(row.original.id); } diff --git a/src/components/IncidentTable/subcomponents/ColumnFilterComponent.jsx b/src/components/IncidentTable/subcomponents/ColumnFilterComponent.jsx index 3693dfe9..ae278826 100644 --- a/src/components/IncidentTable/subcomponents/ColumnFilterComponent.jsx +++ b/src/components/IncidentTable/subcomponents/ColumnFilterComponent.jsx @@ -14,8 +14,7 @@ import { } from '@chakra-ui/react'; import { - IoFunnel, - IoFunnelOutline, + IoFunnel, IoFunnelOutline, } from 'react-icons/io5'; import { diff --git a/src/components/IncidentTable/subcomponents/GetAllModal.jsx b/src/components/IncidentTable/subcomponents/GetAllModal.jsx index 7a3538eb..23176bd0 100644 --- a/src/components/IncidentTable/subcomponents/GetAllModal.jsx +++ b/src/components/IncidentTable/subcomponents/GetAllModal.jsx @@ -46,13 +46,9 @@ const GetAllModal = ({ const rowsFetching = useMemo( () => rowsToExport.filter((row) => { const { - alerts, - notes, + alerts, notes, } = row.original; - return ( - (alerts && alerts.status === 'fetching') - || (notes && notes.status === 'fetching') - ); + return (alerts && alerts.status === 'fetching') || (notes && notes.status === 'fetching'); }), [rowsToExport], ); @@ -60,13 +56,9 @@ const GetAllModal = ({ const rowsDoneFetching = useMemo( () => rowsToExport.filter((row) => { const { - alerts, - notes, + alerts, notes, } = row.original; - return ( - (alerts && alerts instanceof Array) - && (notes && notes instanceof Array) - ); + return alerts && alerts instanceof Array && notes && notes instanceof Array; }), [rowsToExport], ); @@ -79,9 +71,7 @@ const GetAllModal = ({ const fetchRows = useCallback(() => { rowsNeedingFetch.forEach((row) => { const { - id, - notes, - alerts, + id, notes, alerts, } = row.original; if (!notes) { getIncidentNotes(id); @@ -128,11 +118,7 @@ const GetAllModal = ({ {`${rowsFetching.length} remaining`} - + You can close this box and continue using the app, download will continue in the diff --git a/src/components/IncidentTable/subcomponents/IncidentAlertsModal.jsx b/src/components/IncidentTable/subcomponents/IncidentAlertsModal.jsx index 152b2766..0b4c8292 100644 --- a/src/components/IncidentTable/subcomponents/IncidentAlertsModal.jsx +++ b/src/components/IncidentTable/subcomponents/IncidentAlertsModal.jsx @@ -1,9 +1,7 @@ /* eslint-disable no-restricted-syntax */ import React, { - useEffect, - useState, - useMemo, + useEffect, useState, useMemo, } from 'react'; import { @@ -106,16 +104,20 @@ const alertsToCsv = (alerts) => { ]; const header = paths.join(','); - const rows = alerts.map((alert) => paths.map((path) => { - let value = null; - try { - value = path.split('.').reduce((o, i) => o[i], alert); - } catch (e) { /* ignore */ } - if (typeof value === 'string') { - return `"${value.replace(/"/g, '""')}"`; - } - return value; - }).join(',')); + const rows = alerts.map((alert) => paths + .map((path) => { + let value = null; + try { + value = path.split('.').reduce((o, i) => o[i], alert); + } catch (e) { + /* ignore */ + } + if (typeof value === 'string') { + return `"${value.replace(/"/g, '""')}"`; + } + return value; + }) + .join(',')); return `${header}\n${rows.join('\n')}`; }; @@ -128,8 +130,7 @@ const IncidentAlertsModal = () => { showIncidentAlertsModalForIncidentId, } = useSelector((state) => state.settings); const { - filteredIncidentsByQuery, - incidentAlerts, + filteredIncidentsByQuery, incidentAlerts, } = useSelector((state) => state.incidents); const serviceList = useSelector((state) => state.services.services); const serviceListOptions = useMemo(() => { @@ -184,7 +185,9 @@ const IncidentAlertsModal = () => { dispatch(moveAlertsConnected(fromIncidentId, toIncidentId, alertsToMove, options)); }; - const incident = filteredIncidentsByQuery.find((i) => i.id === showIncidentAlertsModalForIncidentId); + const incident = filteredIncidentsByQuery.find( + (i) => i.id === showIncidentAlertsModalForIncidentId, + ); const alerts = incidentAlerts[showIncidentAlertsModalForIncidentId]; const moveToNewIncidentOptions = { @@ -278,8 +281,9 @@ const IncidentAlertsModal = () => { id="alerts-modal-checkbox-all" isChecked={selectedAlerts.length === alertsSortedDescendingDate.length} isIndeterminate={ - selectedAlerts.length > 0 && selectedAlerts.length < alertsSortedDescendingDate.length - } + selectedAlerts.length > 0 + && selectedAlerts.length < alertsSortedDescendingDate.length + } onChange={(e) => { if (e.target.checked) { setSelectedAlerts(alertsSortedDescendingDate.map((alert) => alert.id)); @@ -320,12 +324,7 @@ const IncidentAlertsModal = () => { )} - + {alert.summary} @@ -343,7 +342,9 @@ const IncidentAlertsModal = () => { mr={3} onClick={() => { const alertsCsv = alertsToCsv( - alerts.filter((a) => selectedAlerts.length === 0 || selectedAlerts.includes(a.id)), + alerts.filter( + (a) => selectedAlerts.length === 0 || selectedAlerts.includes(a.id), + ), ); const blob = new Blob([alertsCsv], { type: 'text/csv;charset=utf-8;' }); const url = URL.createObjectURL(blob); @@ -382,11 +383,7 @@ const IncidentAlertsModal = () => { - setShowMoveModal(false)} - size="xl" - > + setShowMoveModal(false)} size="xl"> @@ -395,9 +392,7 @@ const IncidentAlertsModal = () => { - - {t('Move to')} - + {t('Move to')} { /> - - {t('Service')} - + {t('Service')} { ? priorityListOptions.find((s) => s.value === incident.priority.id) : priorityListOptions.find((s) => s.value === '--') } - onChange={ - (selected) => setMoveTargetOptions((prev) => ({ ...prev, priorityId: selected.value })) - } + onChange={(selected) => setMoveTargetOptions((prev) => ({ ...prev, priorityId: selected.value }))} placeholder={`${t('Select dotdotdot')}`} chakraStyles={{ // Ensure that dropdowns appear over table header diff --git a/src/components/IncidentTable/subcomponents/LatestNoteComponent.jsx b/src/components/IncidentTable/subcomponents/LatestNoteComponent.jsx index 1e14257f..3de283b2 100644 --- a/src/components/IncidentTable/subcomponents/LatestNoteComponent.jsx +++ b/src/components/IncidentTable/subcomponents/LatestNoteComponent.jsx @@ -1,6 +1,5 @@ import React, { - useRef, - useState, + useRef, useState, } from 'react'; import { @@ -24,8 +23,7 @@ import { } from '@chakra-ui/react'; import { - AddIcon, - CheckIcon, + AddIcon, CheckIcon, } from '@chakra-ui/icons'; import i18next from 'i18next'; @@ -44,9 +42,7 @@ const LatestNoteComponent = ({ const noteRef = useRef(null); const [note, setNote] = useState(''); const { - isOpen, - onToggle, - onClose, + isOpen, onToggle, onClose, } = useDisclosure(); const dispatch = useDispatch(); const addNote = (incidents, noteContent) => dispatch(addNoteConnected(incidents, noteContent, true, false)); @@ -59,21 +55,14 @@ const LatestNoteComponent = ({ alignItems="center" justifyContent="space-between" > - + {incident.notes?.length > 0 && incident.notes.slice(-1)[0].content} {incident.notes?.length === 0 && '--'} {incident.notes?.status === 'fetching' && fetching} - + - - {i18next.t('Add Note')} - + {i18next.t('Add Note')}