Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Release] v0.1.0 beta.0 #133

Merged
merged 41 commits into from
Jun 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
997a5e9
giranm May 6, 2022
3f2fe72
giranm May 7, 2022
7477001
fix: upgrade moment from 2.29.2 to 2.29.3
snyk-bot May 8, 2022
731a220
Merge pull request #108 from giranm/snyk-upgrade-4517900c4f41f741db4b…
giranm May 8, 2022
2133b6d
Bump html-webpack-plugin from 4.5.2 to 5.5.0
dependabot[bot] May 9, 2022
ef9d98f
Bump eslint-plugin-import from 2.25.4 to 2.26.0
dependabot[bot] May 9, 2022
6646457
Bump use-debounce from 7.0.1 to 8.0.1
dependabot[bot] May 9, 2022
31e920f
Merge pull request #112 from giranm/dependabot/npm_and_yarn/develop/u…
dependabot[bot] May 9, 2022
0cb10d5
Merge pull request #111 from giranm/dependabot/npm_and_yarn/develop/e…
dependabot[bot] May 9, 2022
d1ae603
Merge pull request #109 from giranm/dependabot/npm_and_yarn/develop/h…
dependabot[bot] May 9, 2022
82d0061
Bump prettier from 2.5.1 to 2.6.2
dependabot[bot] May 9, 2022
83bfbcb
Merge pull request #110 from giranm/dependabot/npm_and_yarn/develop/p…
giranm May 9, 2022
2ec8f71
giranm May 25, 2022
72ca275
Initial commit of working branch - testing to be added.
giranm Jun 5, 2022
69c78de
Added component test coverage
giranm Jun 5, 2022
c690c0a
Added custom getRowId to ensure stickiness of selection
giranm Jun 6, 2022
a1ff0b5
Added integration test for coverage
giranm Jun 6, 2022
9f88731
Merge pull request #128 from giranm/fix/row-selection-table-update
giranm Jun 6, 2022
06e0a34
Merge branch 'develop' into task/limit-incidents-queried
giranm Jun 6, 2022
37de572
Added saga test coverage for Fuse Search
giranm Jun 6, 2022
d6c97d0
Changed to title due to longer query
giranm Jun 6, 2022
cde83cc
Merge pull request #129 from giranm/fix/global-search-radius
giranm Jun 6, 2022
848e011
Merge branch 'develop' into task/limit-incidents-queried
giranm Jun 6, 2022
8cc734f
Removed redundant param for API
giranm Jun 7, 2022
0f76ce2
Amended UX for Incident Actions on query cancel
giranm Jun 7, 2022
14f41ec
Used shallow rendering for pure components in test suite
giranm Jun 7, 2022
bca4905
Made ConfirmQueryModalComponent test more prescriptive
giranm Jun 7, 2022
bd9d328
add auth component
martindstone Jun 7, 2022
102ed2f
remove null return from pd-api-wrapper
martindstone Jun 7, 2022
7645d0c
WIP: Working on saga tests but failing D:
giranm Jun 7, 2022
613b824
Fixed integration tests for saga when mocking API - further test tbd.
giranm Jun 9, 2022
ad6a70e
Added remaining integration test coverage
giranm Jun 10, 2022
eb95f66
Added e2e test coverage and minor selector consistency checks
giranm Jun 10, 2022
1f62cdd
Merge pull request #132 from giranm/task/limit-incidents-queried
giranm Jun 10, 2022
333fbe3
Merge branch 'develop' into auth-component
giranm Jun 10, 2022
996a59a
Renamed component and added react-bootstrap implementation
giranm Jun 13, 2022
7962a3a
Decoupled auth specific functions from component and added initial te…
giranm Jun 13, 2022
90dc027
WIP: Adding unit tests for auth functions
giranm Jun 13, 2022
d2bc841
Fixed auth tests and mocking. Code clean up.
giranm Jun 13, 2022
8b15954
Merge pull request #130 from giranm/auth-component
giranm Jun 13, 2022
a788d4b
Publishing release v0.1.0-beta.0
giranm Jun 13, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,16 @@ To prepare PagerDuty Live for release, the current workflow should be carried ou
1. Checkout to `develop` branch and verify if it's stable - i.e. no test and linting failures.

2. Update version information in `package.json` using `npm version` - example commands given below:
- Bumping patch version for alpha release
- Bumping patch version for beta release
```
$ npm --no-git-tag-version version prepatch --preid alpha
v0.0.1-alpha.0
$ npm --no-git-tag-version version preminor --preid beta
v0.1.0-beta.0
```

- Bumping minor version for main release
```
$ npm --no-git-tag-version version minor
v0.1.0
v0.2.0
```

3. Update application code version using `$ yarn genversion`
Expand Down
42 changes: 42 additions & 0 deletions cypress/integration/Query/query.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
checkIncidentCellIconAllRows,
manageIncidentTableColumns,
priorityNames,
selectIncident,
} from '../../support/util/common';

registerLocale('en-GB', gb);
Expand Down Expand Up @@ -67,9 +68,45 @@ describe('Query Incidents', { failFast: { enabled: false } }, () => {

// Reset query for next test
activateButton('query-urgency-low-button');
});

it('Query for incidents exceeding MAX_INCIDENTS_LIMIT; Cancel Request', () => {
// Update since date to T-2
const queryDate = moment()
.subtract(2, 'days')
.set({ hour: 0, minute: 0, second: 0, millisecond: 0 });
cy.get('#query-date-input').clear().type(queryDate.format('DD/MM/yyyy')).type('{enter}');

// Cancel request from modal
cy.get('#cancel-incident-query-button').click();
cy.get('div.query-cancelled-ctr')
.should('be.visible')
.should('contain.text', 'Query has been cancelled by user');
cy.get('div.selected-incidents-ctr').should('be.visible').should('contain.text', 'N/A');

// Reset query for next test
deactivateButton('query-status-resolved-button');
});

it('Query for incidents exceeding MAX_INCIDENTS_LIMIT; Accept Request', () => {
// Accept request from modal
activateButton('query-status-resolved-button');
cy.get('#retrieve-incident-query-button').click();
cy.get('div.query-active-ctr')
.should('be.visible')
.should('contain.text', 'Querying PagerDuty API');
cy.get('div.selected-incidents-ctr').should('be.visible').should('contain.text', 'Querying');
waitForIncidentTable();

// Reset query for next test
deactivateButton('query-status-resolved-button');
const queryDate = moment()
.subtract(1, 'days')
.set({ hour: 0, minute: 0, second: 0, millisecond: 0 });
cy.get('#query-date-input').clear().type(queryDate.format('DD/MM/yyyy')).type('{enter}');
waitForIncidentTable();
});

it('Query for triggered incidents only', () => {
activateButton('query-status-triggered-button');
deactivateButton('query-status-acknowledged-button');
Expand All @@ -79,6 +116,11 @@ describe('Query Incidents', { failFast: { enabled: false } }, () => {
});

it('Query for acknowledged incidents only', () => {
// Ensure at least one incident is acknowledged for test
selectIncident(0);
cy.get('#incident-action-acknowledge-button').click();
cy.get('.action-alerts-modal').type('{esc}');

deactivateButton('query-status-triggered-button');
activateButton('query-status-acknowledged-button');
deactivateButton('query-status-resolved-button');
Expand Down
14 changes: 14 additions & 0 deletions cypress/integration/Search/search.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
waitForIncidentTable,
activateButton,
priorityNames,
selectIncident,
} from '../../support/util/common';

describe('Search Incidents', { failFast: { enabled: false } }, () => {
Expand Down Expand Up @@ -33,6 +34,19 @@ describe('Search Incidents', { failFast: { enabled: false } }, () => {
});
});

it('Search for 2nd selected incident returns exactly 1 incident only', () => {
const incidentIdx = 1;
selectIncident(incidentIdx);
cy.get(`@selectedIncidentId_${incidentIdx}`).then((incidentId) => {
cy.get('#global-search-input').clear().type(incidentId);
});
cy.wait(1000);
cy.get('.selected-incidents-badge').then(($el) => {
const text = $el.text();
expect(text).to.equal('1/1');
});
});

it('Search for `zzzzzz` returns no incidents', () => {
cy.get('#global-search-input').clear().type('zzzzzz');
cy.wait(5000);
Expand Down
1 change: 1 addition & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module.exports = {
testEnvironment: 'jsdom',
testPathIgnorePatterns: ['./cypress/'],
setupFiles: ['dotenv/config'],
setupFilesAfterEnv: ['./setupTests.js'],
moduleDirectories: ['node_modules', 'src'],
moduleNameMapper: {
Expand Down
14 changes: 8 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "pd-live-react",
"homepage": "https://giranm.github.io/pd-live-react",
"version": "0.0.17-alpha.0",
"version": "0.1.0-beta.0",
"private": true,
"dependencies": {
"@craco/craco": "7.0.0-alpha.3",
Expand All @@ -28,7 +28,7 @@
"immer": "^9.0.6",
"lodash": "^4.17.21",
"mezr": "^0.6.2",
"moment": "^2.29.2",
"moment": "^2.29.3",
"node-sass": "^6.0.1",
"react": "^17.0.2",
"react-bootstrap": "^1.6.4",
Expand All @@ -45,7 +45,7 @@
"redux-persist": "^6.0.0",
"redux-saga": "^1.1.3",
"styled-components": "^5.3.5",
"use-debounce": "^7.0.0",
"use-debounce": "^8.0.1",
"web-vitals": "^1.1.2"
},
"resolutions": {
Expand Down Expand Up @@ -90,6 +90,7 @@
"@babel/preset-react": "^7.16.7",
"@cypress/react": "5.12.4",
"@cypress/webpack-dev-server": "^1.8.0",
"@faker-js/faker": "^7.1.0",
"cy2": "^1.3.0",
"cypress": "^9.2.1",
"cypress-fail-fast": "^3.4.1",
Expand All @@ -98,16 +99,17 @@
"eslint-config-prettier": "^8.3.0",
"eslint-config-react-app": "^7.0.0",
"eslint-plugin-cypress": "^2.12.1",
"eslint-plugin-import": "^2.24.2",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jsx-a11y": "^6.4.1",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-react": "^7.26.1",
"eslint-plugin-react-hooks": "^4.2.0",
"genversion": "^3.0.2",
"gh-pages": "^3.2.3",
"html-webpack-plugin": "4",
"html-webpack-plugin": "5",
"identity-obj-proxy": "^3.0.0",
"prettier": "^2.5.1",
"jest-location-mock": "^1.0.9",
"prettier": "^2.6.2",
"prettier-eslint": "^10.1.0",
"prettier-eslint-cli": "^5.0.1",
"redux-mock-store": "^1.5.4",
Expand Down
32 changes: 13 additions & 19 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
} from 'react-bootstrap';
import moment from 'moment';

import AuthComponent from 'components/Auth/AuthComponent';
import UnauthorizedModalComponent from 'components/UnauthorizedModal/UnauthorizedModalComponent';
import DisclaimerModalComponent from 'components/DisclaimerModal/DisclaimerModalComponent';
import NavigationBarComponent from 'components/NavigationBar/NavigationBarComponent';
Expand All @@ -22,11 +23,8 @@ import AddNoteModalComponent from 'components/AddNoteModal/AddNoteModalComponent
import ReassignModalComponent from 'components/ReassignModal/ReassignModalComponent';
import AddResponderModalComponent from 'components/AddResponderModal/AddResponderModalComponent';
import MergeModalComponent from 'components/MergeModal/MergeModalComponent';
import ConfirmQueryModalComponent from 'components/ConfirmQueryModal/ConfirmQueryModalComponent';

import {
getIncidentsAsync as getIncidentsAsyncConnected,
getAllIncidentNotesAsync as getAllIncidentNotesAsyncConnected,
} from 'redux/incidents/actions';
import {
getLogEntriesAsync as getLogEntriesAsyncConnected,
cleanRecentLogEntriesAsync as cleanRecentLogEntriesAsyncConnected,
Expand Down Expand Up @@ -64,12 +62,10 @@ import {
store,
} from 'redux/store';

import PDOAuth from 'util/pdoauth';

import {
PD_REQUIRED_ABILITY,
PD_OAUTH_CLIENT_ID,
PD_OAUTH_CLIENT_SECRET,
PD_REQUIRED_ABILITY,
LOG_ENTRIES_POLLING_INTERVAL_SECONDS,
LOG_ENTRIES_CLEARING_INTERVAL_SECONDS,
} from 'config/constants';
Expand All @@ -90,24 +86,24 @@ const App = ({
getEscalationPoliciesAsync,
getExtensionsAsync,
getResponsePlaysAsync,
getIncidentsAsync,
getAllIncidentNotesAsync,
getLogEntriesAsync,
cleanRecentLogEntriesAsync,
}) => {
// Verify if session token is present
const token = sessionStorage.getItem('pd_access_token');
if (!token) {
useEffect(() => {
PDOAuth.login(PD_OAUTH_CLIENT_ID, PD_OAUTH_CLIENT_SECRET);
}, []);
return null;
return (
<div className="App">
<AuthComponent clientId={PD_OAUTH_CLIENT_ID} clientSecret={PD_OAUTH_CLIENT_SECRET} />
</div>
);
}

// Begin monitoring and load core objects from API
const {
userAuthorized, userAcceptedDisclaimer, currentUserLocale,
} = state.users;
const queryError = state.querySettings.error;
useEffect(() => {
userAuthorize();
if (userAuthorized) {
Expand All @@ -120,8 +116,7 @@ const App = ({
getExtensionsAsync();
getResponsePlaysAsync();
getPrioritiesAsync();
getIncidentsAsync();
getAllIncidentNotesAsync();
// NB: Get Incidents and Notes are implicitly done from query now
checkConnectionStatus();
}
}, [userAuthorized]);
Expand All @@ -139,15 +134,15 @@ const App = ({
const {
abilities,
} = store.getState().connection;
if (userAuthorized && abilities.includes(PD_REQUIRED_ABILITY)) {
if (userAuthorized && abilities.includes(PD_REQUIRED_ABILITY) && !queryError) {
const lastPolledDate = moment()
.subtract(2 * LOG_ENTRIES_POLLING_INTERVAL_SECONDS, 'seconds')
.toDate();
getLogEntriesAsync(lastPolledDate);
}
}, LOG_ENTRIES_POLLING_INTERVAL_SECONDS * 1000);
return () => clearInterval(pollingInterval);
}, [userAuthorized]);
}, [userAuthorized, queryError]);

// Setup log entry clearing
useEffect(() => {
Expand Down Expand Up @@ -191,6 +186,7 @@ const App = ({
<ReassignModalComponent />
<AddResponderModalComponent />
<MergeModalComponent />
<ConfirmQueryModalComponent />
</Container>
</div>
);
Expand All @@ -210,8 +206,6 @@ const mapDispatchToProps = (dispatch) => ({
getEscalationPoliciesAsync: () => dispatch(getEscalationPoliciesAsyncConnected()),
getExtensionsAsync: () => dispatch(getExtensionsAsyncConnected()),
getResponsePlaysAsync: () => dispatch(getResponsePlaysAsyncConnected()),
getIncidentsAsync: () => dispatch(getIncidentsAsyncConnected()),
getAllIncidentNotesAsync: () => dispatch(getAllIncidentNotesAsyncConnected()),
getLogEntriesAsync: (since) => dispatch(getLogEntriesAsyncConnected(since)),
cleanRecentLogEntriesAsync: () => dispatch(cleanRecentLogEntriesAsyncConnected()),
});
Expand Down
87 changes: 87 additions & 0 deletions src/components/Auth/AuthComponent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/* eslint-disable no-unused-vars */
import React, {
useState, useEffect,
} from 'react';

import {
Form, Button, Dropdown, Spinner, Row,
} from 'react-bootstrap';

import {
createCodeVerifier, getAuthURL, exchangeCodeForToken,
} from 'util/auth';

import './AuthComponent.scss';

const AuthComponent = (props) => {
const [authURL, setAuthURL] = useState('');
const urlParams = new URLSearchParams(window.location.search);
const accessToken = sessionStorage.getItem('pd_access_token');
const code = urlParams.get('code');
let codeVerifier = sessionStorage.getItem('code_verifier');
let {
redirectURL,
} = props;
const {
clientId, clientSecret,
} = props;

if (!redirectURL) {
// assume that the redirect URL is the current page
redirectURL = `${window.location.protocol}//${window.location.host}${window.location.pathname}`;
}

useEffect(() => {
if (code && codeVerifier && !accessToken) {
exchangeCodeForToken(clientId, clientSecret, redirectURL, codeVerifier, code).then(
(token) => {
sessionStorage.removeItem('code_verifier');
sessionStorage.setItem('pd_access_token', token);
window.location.assign(redirectURL);
},
);
} else if (!accessToken) {
codeVerifier = createCodeVerifier();
sessionStorage.setItem('code_verifier', codeVerifier);
getAuthURL(clientId, clientSecret, redirectURL, codeVerifier).then((url) => {
setAuthURL(url);
});
}
}, []);

if (code && codeVerifier) {
return (
<div align="center">
<br />
<Row className="justify-content-md-center">
<Spinner animation="border" role="status" variant="success" />
<h5 className="querying-incidents">
<b>Signing into PagerDuty Live</b>
</h5>
</Row>
</div>
);
}
return (
<div align="center">
<Form id="pd-login-form">
<div id="pd-login-logo" />
<Dropdown.Divider />
<div id="pd-login-description">
<h1>Live Incidents Console</h1>
<p>Connect using PagerDuty OAuth to use this app</p>
</div>
<Button
id="pd-login-button"
variant="primary"
size="lg"
onClick={() => window.location.assign(authURL)}
>
Sign In
</Button>
</Form>
</div>
);
};

export default AuthComponent;
Loading