From 15db397e07f9b9c4e326f1bc564601291d347346 Mon Sep 17 00:00:00 2001 From: thomasridd Date: Fri, 9 Feb 2024 17:03:00 +0000 Subject: [PATCH 1/8] add current filter section --- assets/js/initMOJFilterPage.js | 8 ++ server/views/pages/base-clients.njk | 27 ++++++- .../presenters/listBaseClientsPresenter.ts | 74 +++++++++++++++++-- 3 files changed, 97 insertions(+), 12 deletions(-) diff --git a/assets/js/initMOJFilterPage.js b/assets/js/initMOJFilterPage.js index 9900f834..99ed1657 100644 --- a/assets/js/initMOJFilterPage.js +++ b/assets/js/initMOJFilterPage.js @@ -19,3 +19,11 @@ new MOJFrontend.FilterToggleButton({ container: $('.moj-filter'), }, }) + +function moveFilterTagsToResults() { + var newContainer = $('.moj-action-bar__filterTagsContainer') + var tagsContainer = $('.moj-filter__selected') + tagsContainer.appendTo(newContainer) +} + +moveFilterTagsToResults() diff --git a/server/views/pages/base-clients.njk b/server/views/pages/base-clients.njk index 822bfb87..5361f8b2 100644 --- a/server/views/pages/base-clients.njk +++ b/server/views/pages/base-clients.njk @@ -94,21 +94,39 @@ {% endset %} - - {% block content %} -
+
+ {% if presenter.showSelectedFilters %} + {{ mojFilter({ + heading: { + text: 'Filter' + }, + selectedFilters: { + heading: { + text: 'Selected filters' + }, + + clearLink: { + text: 'Clear filters', + href: '/' + }, + + categories: presenter.selectedFilterCategories + }, + optionsHtml: filterOptionsHtml + }) }} + {% else %} {{ mojFilter({ heading: { text: 'Filter' }, - optionsHtml: filterOptionsHtml }) }} + {% endif %}
@@ -136,6 +154,7 @@ } }] }) }} +
diff --git a/server/views/presenters/listBaseClientsPresenter.ts b/server/views/presenters/listBaseClientsPresenter.ts index f9a0dba7..1f15e2d1 100644 --- a/server/views/presenters/listBaseClientsPresenter.ts +++ b/server/views/presenters/listBaseClientsPresenter.ts @@ -137,17 +137,75 @@ export const filterBaseClient = (baseClient: BaseClient, filter: BaseClientListF return true } +type SelectedFilterCategory = { + heading: { text: string } + items: { href: string; text: string }[] +} + +const getSelectedFilterCategories = (filter: BaseClientListFilter): SelectedFilterCategory[] => { + const categories: SelectedFilterCategory[] = [] + if (filter.roleSearch) { + categories.push({ + heading: { + text: 'Role', + }, + items: [{ href: '/base-clients', text: filter.roleSearch }], + }) + } + + if (filter.clientCredentials === false || filter.authorisationCode === false) { + const grantTypesCategory: SelectedFilterCategory = { + heading: { + text: 'Grant type', + }, + items: [], + } + if (filter.clientCredentials) { + grantTypesCategory.items.push({ href: '/base-clients', text: 'Client credentials' }) + } + if (filter.authorisationCode) { + grantTypesCategory.items.push({ href: '/base-clients', text: 'Authorisation code' }) + } + categories.push(grantTypesCategory) + } + + if (filter.personalClientType === false || filter.serviceClientType === false || filter.blankClientType === false) { + const clientTypeCategory: SelectedFilterCategory = { + heading: { + text: 'Client type', + }, + items: [], + } + if (filter.personalClientType) { + clientTypeCategory.items.push({ href: '/base-clients', text: 'Personal' }) + } + if (filter.serviceClientType) { + clientTypeCategory.items.push({ href: '/base-clients', text: 'Service' }) + } + if (filter.blankClientType) { + clientTypeCategory.items.push({ href: '/base-clients', text: 'Blank' }) + } + categories.push(clientTypeCategory) + } + + return categories +} export default (data: BaseClient[], filter?: BaseClientListFilter) => { + const defaultFilter: BaseClientListFilter = { + roleSearch: '', + clientCredentials: true, + authorisationCode: true, + serviceClientType: true, + personalClientType: true, + blankClientType: true, + } + const currentFilter = filter || defaultFilter + return { tableHead: indexTableHead(), tableRows: indexTableRows(data, filter), - filter: filter || { - roleSearch: '', - clientCredentials: true, - authorisationCode: true, - serviceClientType: true, - personalClientType: true, - blankClientType: true, - }, + filter: currentFilter, + showSelectedFilters: JSON.stringify(currentFilter) !== JSON.stringify(defaultFilter), + selectedFilterCategories: getSelectedFilterCategories(currentFilter), } } From d96df1fe27e2dfb1c447c23d766da161537150a3 Mon Sep 17 00:00:00 2001 From: thomasridd Date: Mon, 12 Feb 2024 17:25:01 +0000 Subject: [PATCH 2/8] Add tests for filter logic --- .../listBaseClientsPresenter.test.ts | 172 ++++++++++++++++++ .../presenters/listBaseClientsPresenter.ts | 8 +- 2 files changed, 178 insertions(+), 2 deletions(-) diff --git a/server/views/presenters/listBaseClientsPresenter.test.ts b/server/views/presenters/listBaseClientsPresenter.test.ts index 23793d85..542c2a55 100644 --- a/server/views/presenters/listBaseClientsPresenter.test.ts +++ b/server/views/presenters/listBaseClientsPresenter.test.ts @@ -1,6 +1,8 @@ import { BaseClient } from '../../interfaces/baseClientApi/baseClient' import { baseClientFactory, filterFactory } from '../../testutils/factories' import listBaseClientsPresenter, { filterBaseClient } from './listBaseClientsPresenter' +import { GrantTypes } from '../../data/enums/grantTypes' +import { ClientType } from '../../data/enums/clientTypes' let baseClients: BaseClient[] @@ -105,5 +107,175 @@ describe('listBaseClientsPresenter', () => { expect(passesFilter).toBeFalsy() }) }) + + describe('by grant type', () => { + const clientCredentialsBaseClient = baseClientFactory.build({ grantType: GrantTypes.ClientCredentials }) + const authCodeBaseClient = baseClientFactory.build({ grantType: GrantTypes.AuthorizationCode }) + + it('defaults to matching all types', () => { + const filter = filterFactory.build() + + expect(filterBaseClient(clientCredentialsBaseClient, filter)).toBeTruthy() + expect(filterBaseClient(authCodeBaseClient, filter)).toBeTruthy() + }) + + it('can filter out only client credentials', () => { + const filter = filterFactory.build({ clientCredentials: false }) + + expect(filterBaseClient(clientCredentialsBaseClient, filter)).toBeFalsy() + expect(filterBaseClient(authCodeBaseClient, filter)).toBeTruthy() + }) + + it('can filter out only auth code', () => { + const filter = filterFactory.build({ authorisationCode: false }) + + expect(filterBaseClient(clientCredentialsBaseClient, filter)).toBeTruthy() + expect(filterBaseClient(authCodeBaseClient, filter)).toBeFalsy() + }) + }) + + describe('by client type', () => { + const serviceBaseClient = baseClientFactory.build({ deployment: { clientType: ClientType.Service } }) + const personalBaseClient = baseClientFactory.build({ deployment: { clientType: ClientType.Personal } }) + const blankBaseClient = baseClientFactory.build({ deployment: { clientType: '' } }) + + it('defaults to matching all types', () => { + const filter = filterFactory.build() + + expect(filterBaseClient(serviceBaseClient, filter)).toBeTruthy() + expect(filterBaseClient(personalBaseClient, filter)).toBeTruthy() + expect(filterBaseClient(blankBaseClient, filter)).toBeTruthy() + }) + + it('can filter out service clients', () => { + const filter = filterFactory.build({ serviceClientType: false }) + + expect(filterBaseClient(serviceBaseClient, filter)).toBeFalsy() + expect(filterBaseClient(personalBaseClient, filter)).toBeTruthy() + expect(filterBaseClient(blankBaseClient, filter)).toBeTruthy() + }) + + it('can filter out personal clients', () => { + const filter = filterFactory.build({ personalClientType: false }) + + expect(filterBaseClient(serviceBaseClient, filter)).toBeTruthy() + expect(filterBaseClient(personalBaseClient, filter)).toBeFalsy() + expect(filterBaseClient(blankBaseClient, filter)).toBeTruthy() + }) + + it('can filter out blank clients', () => { + const filter = filterFactory.build({ blankClientType: false }) + + expect(filterBaseClient(serviceBaseClient, filter)).toBeTruthy() + expect(filterBaseClient(personalBaseClient, filter)).toBeTruthy() + expect(filterBaseClient(blankBaseClient, filter)).toBeFalsy() + }) + }) + }) + + describe('filter presenter values', () => { + describe('showSelectedFilters', () => { + it('returns false if no filter is given', () => { + const presenter = listBaseClientsPresenter(baseClients) + + expect(presenter.showSelectedFilters).toBeFalsy() + }) + + it('returns false if no filters are selected', () => { + const filter = filterFactory.build() + const presenter = listBaseClientsPresenter(baseClients, filter) + + expect(presenter.showSelectedFilters).toBeFalsy() + }) + + it('returns true if any filters are selected', () => { + const filter = filterFactory.build({ roleSearch: 'ONE' }) + const presenter = listBaseClientsPresenter(baseClients, filter) + + expect(presenter.showSelectedFilters).toBeTruthy() + }) + }) + + describe('selectedFilterCategories', () => { + it('is empty by default', () => { + const filter = filterFactory.build() + const { selectedFilterCategories } = listBaseClientsPresenter(baseClients, filter) + + expect(selectedFilterCategories).toHaveLength(0) + }) + + it('has a role category if a role search string is applied', () => { + const filter = filterFactory.build({ roleSearch: 'ONE' }) + const { selectedFilterCategories } = listBaseClientsPresenter(baseClients, filter) + + expect(selectedFilterCategories).toHaveLength(1) + expect(selectedFilterCategories[0].heading.text).toEqual('Role') + expect(selectedFilterCategories[0].items[0].text).toEqual('ONE') + }) + + it('has visible grant type category if either of the grant types are deselected', () => { + const filter = filterFactory.build({ clientCredentials: false }) + const { selectedFilterCategories } = listBaseClientsPresenter(baseClients, filter) + + expect(selectedFilterCategories).toHaveLength(1) + expect(selectedFilterCategories[0].heading.text).toEqual('Grant type') + expect(selectedFilterCategories[0].items[0].text).toEqual('Authorisation code') + }) + + it('has no grant type category if all grant types are deselected', () => { + const filter = filterFactory.build({ clientCredentials: false, authorisationCode: false }) + const { selectedFilterCategories } = listBaseClientsPresenter(baseClients, filter) + + expect(selectedFilterCategories).toHaveLength(0) + }) + + it('has visible client type category if single client type is selected', () => { + const filter = filterFactory.build({ serviceClientType: false, personalClientType: false }) + const { selectedFilterCategories } = listBaseClientsPresenter(baseClients, filter) + + expect(selectedFilterCategories).toHaveLength(1) + expect(selectedFilterCategories[0].heading.text).toEqual('Client type') + expect(selectedFilterCategories[0].items[0].text).toEqual('Blank') + }) + + it('has two client type categories if single client type is selected', () => { + const filter = filterFactory.build({ serviceClientType: false }) + const { selectedFilterCategories } = listBaseClientsPresenter(baseClients, filter) + + expect(selectedFilterCategories).toHaveLength(1) + expect(selectedFilterCategories[0].heading.text).toEqual('Client type') + expect(selectedFilterCategories[0].items[0].text).toEqual('Personal') + expect(selectedFilterCategories[0].items[1].text).toEqual('Blank') + }) + + it('has no client type category if no client type is selected', () => { + const filter = filterFactory.build({ + blankClientType: false, + personalClientType: false, + serviceClientType: false, + }) + const { selectedFilterCategories } = listBaseClientsPresenter(baseClients, filter) + + expect(selectedFilterCategories).toHaveLength(0) + }) + + it('can have complex filters with multiple categories', () => { + const filter = filterFactory.build({ + roleSearch: 'ONE', + clientCredentials: false, + serviceClientType: false, + }) + const { selectedFilterCategories } = listBaseClientsPresenter(baseClients, filter) + + expect(selectedFilterCategories).toHaveLength(3) + expect(selectedFilterCategories[0].heading.text).toEqual('Role') + expect(selectedFilterCategories[0].items[0].text).toEqual('ONE') + expect(selectedFilterCategories[1].heading.text).toEqual('Grant type') + expect(selectedFilterCategories[1].items[0].text).toEqual('Authorisation code') + expect(selectedFilterCategories[2].heading.text).toEqual('Client type') + expect(selectedFilterCategories[2].items[0].text).toEqual('Personal') + expect(selectedFilterCategories[2].items[1].text).toEqual('Blank') + }) + }) }) }) diff --git a/server/views/presenters/listBaseClientsPresenter.ts b/server/views/presenters/listBaseClientsPresenter.ts index 1f15e2d1..b385f8ca 100644 --- a/server/views/presenters/listBaseClientsPresenter.ts +++ b/server/views/presenters/listBaseClientsPresenter.ts @@ -166,7 +166,9 @@ const getSelectedFilterCategories = (filter: BaseClientListFilter): SelectedFilt if (filter.authorisationCode) { grantTypesCategory.items.push({ href: '/base-clients', text: 'Authorisation code' }) } - categories.push(grantTypesCategory) + if (grantTypesCategory.items.length > 0) { + categories.push(grantTypesCategory) + } } if (filter.personalClientType === false || filter.serviceClientType === false || filter.blankClientType === false) { @@ -185,7 +187,9 @@ const getSelectedFilterCategories = (filter: BaseClientListFilter): SelectedFilt if (filter.blankClientType) { clientTypeCategory.items.push({ href: '/base-clients', text: 'Blank' }) } - categories.push(clientTypeCategory) + if (clientTypeCategory.items.length > 0) { + categories.push(clientTypeCategory) + } } return categories From 381af341703c79ab619fc98e211cebe5bef5fcf4 Mon Sep 17 00:00:00 2001 From: thomasridd Date: Tue, 13 Feb 2024 09:26:10 +0000 Subject: [PATCH 3/8] redirect from /base-clients to the index --- server/routes/baseClientRouter.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/server/routes/baseClientRouter.ts b/server/routes/baseClientRouter.ts index 228e7173..dd740f14 100644 --- a/server/routes/baseClientRouter.ts +++ b/server/routes/baseClientRouter.ts @@ -18,9 +18,15 @@ export default function baseClientRouter(services: Services): Router { handlers.map(handler => asyncMiddleware(handler)), ) + const redirect = (path: string, redirectPath: string) => + router.get(path, (req, res) => { + res.redirect(redirectPath) + }) + const baseClientController = new BaseClientController(services.baseClientService) get('/', baseClientController.displayBaseClients()) + redirect('/base-clients', '/') get('/base-clients/new', baseClientController.displayNewBaseClient()) get('/base-clients/:baseClientId/deployment', baseClientController.displayEditBaseClientDeployment()) get('/base-clients/:baseClientId/edit', baseClientController.displayEditBaseClient()) From 8c3cd1622601e58217230aae70a9229c7d35fc28 Mon Sep 17 00:00:00 2001 From: thomasridd Date: Tue, 13 Feb 2024 11:49:09 +0000 Subject: [PATCH 4/8] add remove links to filter items --- .../listBaseClientsPresenter.test.ts | 47 ++++++++++++++++++- .../presenters/listBaseClientsPresenter.ts | 33 ++++++++++--- 2 files changed, 73 insertions(+), 7 deletions(-) diff --git a/server/views/presenters/listBaseClientsPresenter.test.ts b/server/views/presenters/listBaseClientsPresenter.test.ts index 542c2a55..246b8dd6 100644 --- a/server/views/presenters/listBaseClientsPresenter.test.ts +++ b/server/views/presenters/listBaseClientsPresenter.test.ts @@ -1,4 +1,4 @@ -import { BaseClient } from '../../interfaces/baseClientApi/baseClient' +import { BaseClient, BaseClientListFilter } from '../../interfaces/baseClientApi/baseClient' import { baseClientFactory, filterFactory } from '../../testutils/factories' import listBaseClientsPresenter, { filterBaseClient } from './listBaseClientsPresenter' import { GrantTypes } from '../../data/enums/grantTypes' @@ -277,5 +277,50 @@ describe('listBaseClientsPresenter', () => { expect(selectedFilterCategories[2].items[1].text).toEqual('Blank') }) }) + + describe('removeFilterLink', () => { + // Given some base clients + const baseClientA = baseClientFactory.build({ + baseClientId: 'baseClientIdA', + count: 1, + clientCredentials: { authorities: ['ONE', 'TWO'] }, + }) + const baseClientB = baseClientFactory.build({ + baseClientId: 'baseClientIdB', + count: 2, + clientCredentials: { authorities: ['ALPHA'] }, + }) + baseClients = [baseClientA, baseClientB] + + // current URL is /?role=ONE&grantType=authorization-code&clientType=personal&clientType=blank + const compoundFilter = filterFactory.build({ + roleSearch: 'ONE', + clientCredentials: false, + serviceClientType: false, + }) + + const presenter = listBaseClientsPresenter(baseClients, compoundFilter) + + it('removes the role search', () => { + const roleItem = presenter.selectedFilterCategories[0].items[0] + const expected = '/?grantType=authorization-code&clientType=personal&clientType=blank' + const actual = roleItem.href + expect(actual).toEqual(expected) + }) + + it('removes the grant category completely if all grant type items removed', () => { + const grantTypeItem = presenter.selectedFilterCategories[1].items[0] + const expected = '/?role=ONE&clientType=personal&clientType=blank' + const actual = grantTypeItem.href + expect(actual).toEqual(expected) + }) + + it('retains the blank clientType item if personal clientType removed', () => { + const clientTypeItem = presenter.selectedFilterCategories[2].items[0] + const expected = '/?role=ONE&grantType=authorization-code&clientType=blank' + const actual = clientTypeItem.href + expect(actual).toEqual(expected) + }) + }) }) }) diff --git a/server/views/presenters/listBaseClientsPresenter.ts b/server/views/presenters/listBaseClientsPresenter.ts index b385f8ca..5a4a97b6 100644 --- a/server/views/presenters/listBaseClientsPresenter.ts +++ b/server/views/presenters/listBaseClientsPresenter.ts @@ -2,6 +2,7 @@ import { BaseClient, BaseClientListFilter } from '../../interfaces/baseClientApi import { convertToTitleCase, dateFormatFromString, snake } from '../../utils/utils' import { GrantTypes } from '../../data/enums/grantTypes' import { ClientType } from '../../data/enums/clientTypes' +import { mapFilterToUrlQuery } from '../../mappers/baseClientApi/listBaseClients' const indexTableHead = () => { return [ @@ -149,7 +150,7 @@ const getSelectedFilterCategories = (filter: BaseClientListFilter): SelectedFilt heading: { text: 'Role', }, - items: [{ href: '/base-clients', text: filter.roleSearch }], + items: [{ href: removeFilterLink(filter, 'roleSearch'), text: filter.roleSearch }], }) } @@ -161,10 +162,10 @@ const getSelectedFilterCategories = (filter: BaseClientListFilter): SelectedFilt items: [], } if (filter.clientCredentials) { - grantTypesCategory.items.push({ href: '/base-clients', text: 'Client credentials' }) + grantTypesCategory.items.push({ href: removeFilterLink(filter, 'clientCredentials'), text: 'Client credentials' }) } if (filter.authorisationCode) { - grantTypesCategory.items.push({ href: '/base-clients', text: 'Authorisation code' }) + grantTypesCategory.items.push({ href: removeFilterLink(filter, 'authorisationCode'), text: 'Authorisation code' }) } if (grantTypesCategory.items.length > 0) { categories.push(grantTypesCategory) @@ -179,13 +180,13 @@ const getSelectedFilterCategories = (filter: BaseClientListFilter): SelectedFilt items: [], } if (filter.personalClientType) { - clientTypeCategory.items.push({ href: '/base-clients', text: 'Personal' }) + clientTypeCategory.items.push({ href: removeFilterLink(filter, 'personalClientType'), text: 'Personal' }) } if (filter.serviceClientType) { - clientTypeCategory.items.push({ href: '/base-clients', text: 'Service' }) + clientTypeCategory.items.push({ href: removeFilterLink(filter, 'serviceClientType'), text: 'Service' }) } if (filter.blankClientType) { - clientTypeCategory.items.push({ href: '/base-clients', text: 'Blank' }) + clientTypeCategory.items.push({ href: removeFilterLink(filter, 'blankClientType'), text: 'Blank' }) } if (clientTypeCategory.items.length > 0) { categories.push(clientTypeCategory) @@ -194,6 +195,26 @@ const getSelectedFilterCategories = (filter: BaseClientListFilter): SelectedFilt return categories } + +const removeFilterLink = (filter: BaseClientListFilter, filterToRemove: string): string => { + const newFilter: BaseClientListFilter = { ...filter } + if (filterToRemove === 'roleSearch') { + newFilter.roleSearch = '' + } else if (filterToRemove === 'clientCredentials') { + newFilter.clientCredentials = false + } else if (filterToRemove === 'authorisationCode') { + newFilter.authorisationCode = false + } else if (filterToRemove === 'personalClientType') { + newFilter.personalClientType = false + } else if (filterToRemove === 'serviceClientType') { + newFilter.serviceClientType = false + } else if (filterToRemove === 'blankClientType') { + newFilter.blankClientType = false + } + const query = mapFilterToUrlQuery(newFilter) + return query ? `/?${query}` : '/' +} + export default (data: BaseClient[], filter?: BaseClientListFilter) => { const defaultFilter: BaseClientListFilter = { roleSearch: '', From 950953f69f36716e32ae1d371f1a113c7c1d91dd Mon Sep 17 00:00:00 2001 From: thomasridd Date: Wed, 14 Feb 2024 09:36:08 +0000 Subject: [PATCH 5/8] update dependencies --- package-lock.json | 158 ++++++++++-------- package.json | 6 +- .../listBaseClientsPresenter.test.ts | 2 +- 3 files changed, 91 insertions(+), 75 deletions(-) diff --git a/package-lock.json b/package-lock.json index 66b51d8e..631cd14c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,7 +22,7 @@ "connect-flash": "^0.1.1", "connect-redis": "^7.1.1", "csurf": "^1.11.0", - "date-fns": "^2.30.0", + "date-fns": "^3.3.1", "express": "^4.18.2", "express-prom-bundle": "^7.0.0", "express-session": "^1.18.0", @@ -62,8 +62,8 @@ "@types/superagent": "^8.1.3", "@types/supertest": "^6.0.2", "@types/uuid": "^9.0.8", - "@typescript-eslint/eslint-plugin": "^6.20.0", - "@typescript-eslint/parser": "^6.20.0", + "@typescript-eslint/eslint-plugin": "^7.0.1", + "@typescript-eslint/parser": "^7.0.1", "audit-ci": "^6.6.1", "concurrently": "^8.2.2", "cookie-session": "^2.1.0", @@ -1332,10 +1332,12 @@ } }, "node_modules/@babel/runtime": { - "version": "7.22.6", - "license": "MIT", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", + "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", + "dev": true, "dependencies": { - "regenerator-runtime": "^0.13.11" + "regenerator-runtime": "^0.14.0" }, "engines": { "node": ">=6.9.0" @@ -3100,9 +3102,9 @@ "license": "MIT" }, "node_modules/@types/semver": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", - "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.7.tgz", + "integrity": "sha512-/wdoPq1QqkSj9/QOeKkFquEuPzQbHTWAMPH/PaUMB+JuR31lXhlWXRZ52IpfDYVlDOUBvX09uBrPwxGT1hjNBg==", "dev": true }, "node_modules/@types/send": { @@ -3191,16 +3193,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", - "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.0.1.tgz", + "integrity": "sha512-OLvgeBv3vXlnnJGIAgCLYKjgMEU+wBGj07MQ/nxAaON+3mLzX7mJbhRYrVGiVvFiXtwFlkcBa/TtmglHy0UbzQ==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/type-utils": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", + "@typescript-eslint/scope-manager": "7.0.1", + "@typescript-eslint/type-utils": "7.0.1", + "@typescript-eslint/utils": "7.0.1", + "@typescript-eslint/visitor-keys": "7.0.1", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -3216,8 +3218,8 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", - "eslint": "^7.0.0 || ^8.0.0" + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -3226,15 +3228,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", - "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.0.1.tgz", + "integrity": "sha512-8GcRRZNzaHxKzBPU3tKtFNing571/GwPBeCvmAUw0yBtfE2XVd0zFKJIMSWkHJcPQi0ekxjIts6L/rrZq5cxGQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", + "@typescript-eslint/scope-manager": "7.0.1", + "@typescript-eslint/types": "7.0.1", + "@typescript-eslint/typescript-estree": "7.0.1", + "@typescript-eslint/visitor-keys": "7.0.1", "debug": "^4.3.4" }, "engines": { @@ -3245,7 +3247,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -3254,13 +3256,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", - "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.0.1.tgz", + "integrity": "sha512-v7/T7As10g3bcWOOPAcbnMDuvctHzCFYCG/8R4bK4iYzdFqsZTbXGln0cZNVcwQcwewsYU2BJLay8j0/4zOk4w==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0" + "@typescript-eslint/types": "7.0.1", + "@typescript-eslint/visitor-keys": "7.0.1" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -3271,13 +3273,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", - "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.0.1.tgz", + "integrity": "sha512-YtT9UcstTG5Yqy4xtLiClm1ZpM/pWVGFnkAa90UfdkkZsR1eP2mR/1jbHeYp8Ay1l1JHPyGvoUYR6o3On5Nhmw==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/typescript-estree": "7.0.1", + "@typescript-eslint/utils": "7.0.1", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -3289,7 +3291,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -3298,9 +3300,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", - "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.0.1.tgz", + "integrity": "sha512-uJDfmirz4FHib6ENju/7cz9SdMSkeVvJDK3VcMFvf/hAShg8C74FW+06MaQPODHfDJp/z/zHfgawIJRjlu0RLg==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -3311,13 +3313,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", - "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.0.1.tgz", + "integrity": "sha512-SO9wHb6ph0/FN5OJxH4MiPscGah5wjOd0RRpaLvuBv9g8565Fgu0uMySFEPqwPHiQU90yzJ2FjRYKGrAhS1xig==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", + "@typescript-eslint/types": "7.0.1", + "@typescript-eslint/visitor-keys": "7.0.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -3363,17 +3365,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", - "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.0.1.tgz", + "integrity": "sha512-oe4his30JgPbnv+9Vef1h48jm0S6ft4mNwi9wj7bX10joGn07QRfqIqFHoMiajrtoU88cIhXf8ahwgrcbNLgPA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/scope-manager": "7.0.1", + "@typescript-eslint/types": "7.0.1", + "@typescript-eslint/typescript-estree": "7.0.1", "semver": "^7.5.4" }, "engines": { @@ -3384,16 +3386,16 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^8.56.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", - "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.0.1.tgz", + "integrity": "sha512-hwAgrOyk++RTXrP4KzCg7zB2U0xt7RUU0ZdMSCsqF3eKUwkdXUMyTb0qdCuji7VIbcpG62kKTU9M1J1c9UpFBw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/types": "7.0.1", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -4691,6 +4693,22 @@ "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" } }, + "node_modules/concurrently/node_modules/date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, "node_modules/confusing-browser-globals": { "version": "1.0.11", "dev": true, @@ -5026,17 +5044,12 @@ } }, "node_modules/date-fns": { - "version": "2.30.0", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.21.0" - }, - "engines": { - "node": ">=0.11" - }, + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.3.1.tgz", + "integrity": "sha512-y8e109LYGgoQDveiEBD3DYXKba1jWf5BA8YU1FL5Tvm0BTdEfy54WLCwnuYWZNnzzvALy/QQ4Hov+Q9RVRv+Zw==", "funding": { - "type": "opencollective", - "url": "https://opencollective.com/date-fns" + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" } }, "node_modules/dateformat": { @@ -10196,8 +10209,10 @@ } }, "node_modules/regenerator-runtime": { - "version": "0.13.11", - "license": "MIT" + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true }, "node_modules/regexp.prototype.flags": { "version": "1.5.1", @@ -11096,11 +11111,12 @@ } }, "node_modules/ts-api-utils": { - "version": "1.0.3", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.2.1.tgz", + "integrity": "sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA==", "dev": true, - "license": "MIT", "engines": { - "node": ">=16.13.0" + "node": ">=16" }, "peerDependencies": { "typescript": ">=4.2.0" diff --git a/package.json b/package.json index 89b84df1..0060702a 100644 --- a/package.json +++ b/package.json @@ -103,7 +103,7 @@ "bunyan-format": "^0.2.1", "compression": "^1.7.4", "connect-flash": "^0.1.1", - "date-fns": "^2.30.0", + "date-fns": "^3.3.1", "express": "^4.18.2", "express-prom-bundle": "^7.0.0", "fishery": "^2.2.2", @@ -150,8 +150,8 @@ "@types/superagent": "^8.1.3", "@types/supertest": "^6.0.2", "@types/uuid": "^9.0.8", - "@typescript-eslint/eslint-plugin": "^6.20.0", - "@typescript-eslint/parser": "^6.20.0", + "@typescript-eslint/eslint-plugin": "^7.0.1", + "@typescript-eslint/parser": "^7.0.1", "audit-ci": "^6.6.1", "concurrently": "^8.2.2", "cookie-session": "^2.1.0", diff --git a/server/views/presenters/listBaseClientsPresenter.test.ts b/server/views/presenters/listBaseClientsPresenter.test.ts index 246b8dd6..42073a08 100644 --- a/server/views/presenters/listBaseClientsPresenter.test.ts +++ b/server/views/presenters/listBaseClientsPresenter.test.ts @@ -1,4 +1,4 @@ -import { BaseClient, BaseClientListFilter } from '../../interfaces/baseClientApi/baseClient' +import { BaseClient } from '../../interfaces/baseClientApi/baseClient' import { baseClientFactory, filterFactory } from '../../testutils/factories' import listBaseClientsPresenter, { filterBaseClient } from './listBaseClientsPresenter' import { GrantTypes } from '../../data/enums/grantTypes' From 0d8044bd643d1953880757db5412c8f3f599514f Mon Sep 17 00:00:00 2001 From: thomasridd Date: Thu, 29 Feb 2024 10:08:35 +0000 Subject: [PATCH 6/8] Rename GrantTypes to make singular --- integration_tests/e2e/edit-base-client-deployment.cy.ts | 6 +++--- integration_tests/e2e/edit-base-client-details.cy.ts | 8 ++++---- integration_tests/e2e/edit-client-instances.cy.ts | 4 ++-- integration_tests/e2e/login.cy.ts | 4 ++-- integration_tests/e2e/view-base-client-list.cy.ts | 6 +++--- integration_tests/e2e/view-base-client.cy.ts | 8 ++++---- integration_tests/mockApis/baseClientsApi.ts | 4 ++-- server/controllers/baseClientController.ts | 4 ++-- server/data/enums/{grantTypes.ts => grantType.ts} | 2 +- server/data/localMockData/baseClientsResponseMock.ts | 6 +++--- server/interfaces/baseClientApi/baseClient.ts | 2 ++ server/mappers/forms/mapEditBaseClientDetailsForm.test.ts | 8 ++++---- 12 files changed, 32 insertions(+), 30 deletions(-) rename server/data/enums/{grantTypes.ts => grantType.ts} (86%) diff --git a/integration_tests/e2e/edit-base-client-deployment.cy.ts b/integration_tests/e2e/edit-base-client-deployment.cy.ts index 5e5a882c..019c07bf 100644 --- a/integration_tests/e2e/edit-base-client-deployment.cy.ts +++ b/integration_tests/e2e/edit-base-client-deployment.cy.ts @@ -1,7 +1,7 @@ import Page from '../pages/page' import ViewBaseClientPage from '../pages/viewBaseClient' import EditBaseClientDeploymentDetailsPage from '../pages/editBaseClientDeploymentDetails' -import { GrantTypes } from '../../server/data/enums/grantTypes' +import { GrantType } from '../../server/data/enums/grantType' import AuthSignInPage from '../pages/authSignIn' import AuthErrorPage from '../pages/authError' @@ -16,7 +16,7 @@ context('Edit base client deployment: Auth', () => { cy.task('stubSignIn') cy.task('stubManageUser') cy.task('stubListBaseClients') - cy.task('stubGetBaseClient', { grantType: GrantTypes.ClientCredentials }) + cy.task('stubGetBaseClient', { grantType: GrantType.ClientCredentials }) cy.task('stubGetListClientInstancesList') }) @@ -41,7 +41,7 @@ context('Edit base client deployment details page', () => { cy.task('stubSignIn') cy.task('stubManageUser') cy.task('stubListBaseClients') - cy.task('stubGetBaseClient', { grantType: GrantTypes.ClientCredentials }) + cy.task('stubGetBaseClient', { grantType: GrantType.ClientCredentials }) cy.task('stubGetListClientInstancesList') editBaseClientDeploymentDetailsPage = visitEditBaseClientDeploymentDetailsPage() }) diff --git a/integration_tests/e2e/edit-base-client-details.cy.ts b/integration_tests/e2e/edit-base-client-details.cy.ts index 41c4f777..8c039751 100644 --- a/integration_tests/e2e/edit-base-client-details.cy.ts +++ b/integration_tests/e2e/edit-base-client-details.cy.ts @@ -1,7 +1,7 @@ import Page from '../pages/page' import EditBaseClientDetailsPage from '../pages/editBaseClientDetails' import ViewBaseClientPage from '../pages/viewBaseClient' -import { GrantTypes } from '../../server/data/enums/grantTypes' +import { GrantType } from '../../server/data/enums/grantType' import AuthSignInPage from '../pages/authSignIn' import AuthErrorPage from '../pages/authError' @@ -16,7 +16,7 @@ context('Edit base client details: Auth', () => { cy.task('stubSignIn') cy.task('stubManageUser') cy.task('stubListBaseClients') - cy.task('stubGetBaseClient', { grantType: GrantTypes.ClientCredentials }) + cy.task('stubGetBaseClient', { grantType: GrantType.ClientCredentials }) cy.task('stubGetListClientInstancesList') }) @@ -41,7 +41,7 @@ context('Edit base client details page - client-credentials flow', () => { cy.task('stubSignIn') cy.task('stubManageUser') cy.task('stubListBaseClients') - cy.task('stubGetBaseClient', { grantType: GrantTypes.ClientCredentials }) + cy.task('stubGetBaseClient', { grantType: GrantType.ClientCredentials }) cy.task('stubGetListClientInstancesList') cy.task('stubAuthManageDetails') editBaseClientDetailsPage = visitEditBaseClientDetailsPage() @@ -126,7 +126,7 @@ context('Edit base client details page - authorization-code flow', () => { cy.task('stubSignIn') cy.task('stubManageUser') cy.task('stubListBaseClients') - cy.task('stubGetBaseClient', { grantType: GrantTypes.AuthorizationCode }) + cy.task('stubGetBaseClient', { grantType: GrantType.AuthorizationCode }) cy.task('stubGetListClientInstancesList') editBaseClientDetailsPage = visitEditBaseClientDetailsPage() }) diff --git a/integration_tests/e2e/edit-client-instances.cy.ts b/integration_tests/e2e/edit-client-instances.cy.ts index 189d60cc..1995ee76 100644 --- a/integration_tests/e2e/edit-client-instances.cy.ts +++ b/integration_tests/e2e/edit-client-instances.cy.ts @@ -2,7 +2,7 @@ import Page from '../pages/page' import ViewBaseClientPage from '../pages/viewBaseClient' import ViewClientSecretsPage from '../pages/viewClientSecrets' import ConfirmDeleteClientPage from '../pages/confirmDeleteClient' -import { GrantTypes } from '../../server/data/enums/grantTypes' +import { GrantType } from '../../server/data/enums/grantType' const visitBaseClientPage = (): ViewBaseClientPage => { cy.signIn({ failOnStatusCode: true, redirectPath: '/base-clients/base_client_id_1' }) @@ -21,7 +21,7 @@ context('Base client page - client instances', () => { beforeEach(() => { cy.task('reset') cy.task('stubSignIn') - cy.task('stubGetBaseClient', { grantType: GrantTypes.ClientCredentials }) + cy.task('stubGetBaseClient', { grantType: GrantType.ClientCredentials }) cy.task('stubManageUser') cy.task('stubGetListClientInstancesList') }) diff --git a/integration_tests/e2e/login.cy.ts b/integration_tests/e2e/login.cy.ts index 6d62a3fd..3c309d4e 100644 --- a/integration_tests/e2e/login.cy.ts +++ b/integration_tests/e2e/login.cy.ts @@ -2,7 +2,7 @@ import IndexPage from '../pages/index' import AuthSignInPage from '../pages/authSignIn' import Page from '../pages/page' import AuthManageDetailsPage from '../pages/authManageDetails' -import { GrantTypes } from '../../server/data/enums/grantTypes' +import { GrantType } from '../../server/data/enums/grantType' import AuthErrorPage from '../pages/authError' context('SignIn', () => { @@ -10,7 +10,7 @@ context('SignIn', () => { cy.task('reset') cy.task('stubSignIn', ['ROLE_OAUTH_ADMIN']) cy.task('stubListBaseClients') - cy.task('stubGetBaseClient', { grantType: GrantTypes.ClientCredentials }) + cy.task('stubGetBaseClient', { grantType: GrantType.ClientCredentials }) cy.task('stubManageUser') cy.task('stubAuthManageDetails') }) diff --git a/integration_tests/e2e/view-base-client-list.cy.ts b/integration_tests/e2e/view-base-client-list.cy.ts index e0438a04..8df7db90 100644 --- a/integration_tests/e2e/view-base-client-list.cy.ts +++ b/integration_tests/e2e/view-base-client-list.cy.ts @@ -2,7 +2,7 @@ import Page from '../pages/page' import ViewBaseClientListPage from '../pages/viewBaseClientList' import ViewBaseClientPage from '../pages/viewBaseClient' import NewBaseClientGrantPage from '../pages/newBaseClientGrant' -import { GrantTypes } from '../../server/data/enums/grantTypes' +import { GrantType } from '../../server/data/enums/grantType' import AuthSignInPage from '../pages/authSignIn' import AuthErrorPage from '../pages/authError' @@ -17,7 +17,7 @@ context('Homepage - Auth', () => { cy.task('reset') cy.task('stubSignIn') cy.task('stubListBaseClients') - cy.task('stubGetBaseClient', { grantType: GrantTypes.ClientCredentials }) + cy.task('stubGetBaseClient', { grantType: GrantType.ClientCredentials }) cy.task('stubManageUser') cy.task('stubGetListClientInstancesList') }) @@ -42,7 +42,7 @@ context('Homepage - list base-clients', () => { cy.task('reset') cy.task('stubSignIn') cy.task('stubListBaseClients') - cy.task('stubGetBaseClient', { grantType: GrantTypes.ClientCredentials }) + cy.task('stubGetBaseClient', { grantType: GrantType.ClientCredentials }) cy.task('stubManageUser') cy.task('stubGetListClientInstancesList') diff --git a/integration_tests/e2e/view-base-client.cy.ts b/integration_tests/e2e/view-base-client.cy.ts index 98e7304f..d78788d3 100644 --- a/integration_tests/e2e/view-base-client.cy.ts +++ b/integration_tests/e2e/view-base-client.cy.ts @@ -4,7 +4,7 @@ import ViewClientSecretsPage from '../pages/viewClientSecrets' import ConfirmDeleteClientPage from '../pages/confirmDeleteClient' import EditBaseClientDetailsPage from '../pages/editBaseClientDetails' import EditBaseClientDeploymentDetailsPage from '../pages/editBaseClientDeploymentDetails' -import { GrantTypes } from '../../server/data/enums/grantTypes' +import { GrantType } from '../../server/data/enums/grantType' import AuthSignInPage from '../pages/authSignIn' import AuthErrorPage from '../pages/authError' @@ -17,7 +17,7 @@ context('Base client page - Auth', () => { beforeEach(() => { cy.task('reset') cy.task('stubSignIn') - cy.task('stubGetBaseClient', { grantType: GrantTypes.ClientCredentials }) + cy.task('stubGetBaseClient', { grantType: GrantType.ClientCredentials }) cy.task('stubManageUser') cy.task('stubGetListClientInstancesList') cy.task('stubAddClientInstance') @@ -42,7 +42,7 @@ context('Base client page - client credentials flow', () => { beforeEach(() => { cy.task('reset') cy.task('stubSignIn') - cy.task('stubGetBaseClient', { grantType: GrantTypes.ClientCredentials }) + cy.task('stubGetBaseClient', { grantType: GrantType.ClientCredentials }) cy.task('stubManageUser') cy.task('stubGetListClientInstancesList') cy.task('stubAddClientInstance') @@ -115,7 +115,7 @@ context('Base client page - authorization-code flow', () => { beforeEach(() => { cy.task('reset') cy.task('stubSignIn') - cy.task('stubGetBaseClient', { grantType: GrantTypes.AuthorizationCode }) + cy.task('stubGetBaseClient', { grantType: GrantType.AuthorizationCode }) cy.task('stubManageUser') cy.task('stubGetListClientInstancesList') cy.task('stubAddClientInstance') diff --git a/integration_tests/mockApis/baseClientsApi.ts b/integration_tests/mockApis/baseClientsApi.ts index e7b682d2..99061c05 100644 --- a/integration_tests/mockApis/baseClientsApi.ts +++ b/integration_tests/mockApis/baseClientsApi.ts @@ -5,7 +5,7 @@ import { getListClientInstancesResponseMock, getSecretsResponseMock, } from '../../server/data/localMockData/baseClientsResponseMock' -import { GrantTypes } from '../../server/data/enums/grantTypes' +import { GrantType } from '../../server/data/enums/grantType' export default { stubListBaseClients: () => { @@ -24,7 +24,7 @@ export default { }) }, - stubGetBaseClient: (config: { grantType: GrantTypes }) => { + stubGetBaseClient: (config: { grantType: GrantType }) => { return stubFor({ request: { method: 'GET', diff --git a/server/controllers/baseClientController.ts b/server/controllers/baseClientController.ts index 97cea587..47e53fe1 100644 --- a/server/controllers/baseClientController.ts +++ b/server/controllers/baseClientController.ts @@ -7,7 +7,7 @@ import { mapCreateBaseClientForm, mapEditBaseClientDeploymentForm, mapEditBaseCl import { BaseClient, BaseClientListFilter, ClientSecrets } from '../interfaces/baseClientApi/baseClient' import editBaseClientPresenter from '../views/presenters/editBaseClientPresenter' import mapFilterForm from '../mappers/forms/mapFilterForm' -import { GrantTypes } from '../data/enums/grantTypes' +import { GrantType } from '../data/enums/grantType' import { kebab } from '../utils/utils' import baseClientAudit, { BaseClientAuditFunction } from '../audit/baseClientAudit' import { BaseClientEvent } from '../audit/baseClientEvent' @@ -71,7 +71,7 @@ export default class BaseClientController { public displayNewBaseClient(): RequestHandler { return async (req, res) => { const { grant } = req.query - if (!(grant === kebab(GrantTypes.ClientCredentials) || grant === kebab(GrantTypes.AuthorizationCode))) { + if (!(grant === kebab(GrantType.ClientCredentials) || grant === kebab(GrantType.AuthorizationCode))) { res.render('pages/new-base-client-grant.njk', { enableAuthorizationCode }) return } diff --git a/server/data/enums/grantTypes.ts b/server/data/enums/grantType.ts similarity index 86% rename from server/data/enums/grantTypes.ts rename to server/data/enums/grantType.ts index 68c49d21..23601078 100644 --- a/server/data/enums/grantTypes.ts +++ b/server/data/enums/grantType.ts @@ -1,5 +1,5 @@ // eslint-disable-next-line no-shadow,import/prefer-default-export -export enum GrantTypes { +export enum GrantType { ClientCredentials = 'client_credentials', AuthorizationCode = 'authorization_code', } diff --git a/server/data/localMockData/baseClientsResponseMock.ts b/server/data/localMockData/baseClientsResponseMock.ts index 1bde937d..8c57c985 100644 --- a/server/data/localMockData/baseClientsResponseMock.ts +++ b/server/data/localMockData/baseClientsResponseMock.ts @@ -4,7 +4,7 @@ import { ListBaseClientsResponse, ListClientInstancesResponse, } from '../../interfaces/baseClientApi/baseClientResponse' -import { GrantTypes } from '../enums/grantTypes' +import { GrantType } from '../enums/grantType' import { MfaType } from '../enums/mfaTypes' import { snake } from '../../utils/utils' @@ -36,7 +36,7 @@ export const listBaseClientsResponseMock: ListBaseClientsResponse = { ], } -export const getBaseClientResponseMock: (grantType: GrantTypes) => GetBaseClientResponse = (grantType: GrantTypes) => { +export const getBaseClientResponseMock: (grantType: GrantType) => GetBaseClientResponse = (grantType: GrantType) => { const response: GetBaseClientResponse = { grantType: 'CLIENT_CREDENTIALS', clientId: 'base_client_id_1', @@ -59,7 +59,7 @@ export const getBaseClientResponseMock: (grantType: GrantTypes) => GetBaseClient deploymentInfo: 'deployment deployment info', }, } - if (snake(grantType) === GrantTypes.ClientCredentials) { + if (snake(grantType) === GrantType.ClientCredentials) { return { ...response, grantType: 'CLIENT_CREDENTIALS', diff --git a/server/interfaces/baseClientApi/baseClient.ts b/server/interfaces/baseClientApi/baseClient.ts index 67798f59..0cde357c 100644 --- a/server/interfaces/baseClientApi/baseClient.ts +++ b/server/interfaces/baseClientApi/baseClient.ts @@ -1,4 +1,6 @@ import { MfaType } from '../../data/enums/mfaTypes' +import { GrantType } from '../../data/enums/grantType' +import { ClientType } from '../../data/enums/clientTypes' export interface BaseClient { baseClientId: string diff --git a/server/mappers/forms/mapEditBaseClientDetailsForm.test.ts b/server/mappers/forms/mapEditBaseClientDetailsForm.test.ts index 357b7fb9..305268be 100644 --- a/server/mappers/forms/mapEditBaseClientDetailsForm.test.ts +++ b/server/mappers/forms/mapEditBaseClientDetailsForm.test.ts @@ -3,7 +3,7 @@ import { createMock } from '@golevelup/ts-jest' import { baseClientFactory } from '../../testutils/factories' import { dateISOString, offsetNow } from '../../utils/utils' import { mapEditBaseClientDetailsForm } from '../index' -import { GrantTypes } from '../../data/enums/grantTypes' +import { GrantType } from '../../data/enums/grantType' import { MfaType } from '../../data/enums/mfaTypes' const formRequest = (form: Record) => { @@ -99,7 +99,7 @@ describe('mapEditBaseClientDetailsForm', () => { baseClientId: detailedBaseClient.baseClientId, approvedScopes: 'requestscope1,requestscope2', audit: 'request audit', - grantType: GrantTypes.ClientCredentials, + grantType: GrantType.ClientCredentials, authorities: 'requestauthority1\r\nrequestauthority2', databaseUsername: 'request databaseUsername', allowedIPs: 'requestallowedIP1\r\nrequestallowedIP2', @@ -114,7 +114,7 @@ describe('mapEditBaseClientDetailsForm', () => { expect(update.baseClientId).toEqual(detailedBaseClient.baseClientId) expect(update.scopes).toEqual(['requestscope1', 'requestscope2']) expect(update.audit).toEqual('request audit') - expect(update.grantType).toEqual(GrantTypes.ClientCredentials) + expect(update.grantType).toEqual(GrantType.ClientCredentials) expect(update.clientCredentials.authorities).toEqual(['requestauthority1', 'requestauthority2']) expect(update.clientCredentials.databaseUserName).toEqual('request databaseUsername') expect(update.config.allowedIPs).toEqual(['requestallowedIP1', 'requestallowedIP2']) @@ -141,7 +141,7 @@ describe('mapEditBaseClientDetailsForm', () => { baseClientId: detailedBaseClient.baseClientId, approvedScopes: 'requestscope1,requestscope2', audit: 'request audit', - grantType: GrantTypes.AuthorizationCode, + grantType: GrantType.AuthorizationCode, redirectUris: 'requestredirectUri1\r\nrequestredirectUri2', jwtFields: 'request jwtFields', azureAdLoginFlow: 'redirect', From dbaf51e3acf0d1fda43390a278185d2f91ed71bc Mon Sep 17 00:00:00 2001 From: thomasridd Date: Mon, 4 Mar 2024 11:40:21 +0000 Subject: [PATCH 7/8] Alter structure of filters and update UI --- server/data/enums/clientTypes.ts | 17 ++ server/data/enums/grantType.ts | 13 ++ server/interfaces/baseClientApi/baseClient.ts | 10 +- .../baseClientApi/listBaseClients.test.ts | 151 +++---------- .../mappers/baseClientApi/listBaseClients.ts | 62 ++---- server/mappers/forms/mapFilterForm.test.ts | 50 ++--- server/mappers/forms/mapFilterForm.ts | 30 ++- server/testutils/factories/filter.ts | 9 +- server/views/pages/base-clients.njk | 83 ++++--- server/views/partials/list_filter.njk | 83 ------- .../listBaseClientsPresenter.test.ts | 96 ++++---- .../presenters/listBaseClientsPresenter.ts | 209 ++++++++++-------- 12 files changed, 354 insertions(+), 459 deletions(-) delete mode 100644 server/views/partials/list_filter.njk diff --git a/server/data/enums/clientTypes.ts b/server/data/enums/clientTypes.ts index d49ead67..86fcc998 100644 --- a/server/data/enums/clientTypes.ts +++ b/server/data/enums/clientTypes.ts @@ -1,5 +1,22 @@ +import { snake } from '../../utils/utils' + // eslint-disable-next-line no-shadow,import/prefer-default-export export enum ClientType { Personal = 'personal', Service = 'service', + Blank = 'blank', +} + +export const toClientType = (type: string): ClientType => { + const value = snake(type) + if (value === 'personal') { + return ClientType.Personal + } + if (value === 'service') { + return ClientType.Service + } + if (value === '' || value === 'blank') { + return ClientType.Blank + } + throw new Error(`Invalid client type: ${value}`) } diff --git a/server/data/enums/grantType.ts b/server/data/enums/grantType.ts index 23601078..afaa531f 100644 --- a/server/data/enums/grantType.ts +++ b/server/data/enums/grantType.ts @@ -1,5 +1,18 @@ +import { snake } from '../../utils/utils' + // eslint-disable-next-line no-shadow,import/prefer-default-export export enum GrantType { ClientCredentials = 'client_credentials', AuthorizationCode = 'authorization_code', } + +export const toGrantType = (type: string): GrantType => { + const value = snake(type) + if (value === 'client_credentials') { + return GrantType.ClientCredentials + } + if (value === 'authorization_code') { + return GrantType.AuthorizationCode + } + throw new Error(`Invalid grant type: ${value}`) +} diff --git a/server/interfaces/baseClientApi/baseClient.ts b/server/interfaces/baseClientApi/baseClient.ts index 0cde357c..77b493cd 100644 --- a/server/interfaces/baseClientApi/baseClient.ts +++ b/server/interfaces/baseClientApi/baseClient.ts @@ -39,6 +39,7 @@ interface ServiceDetails { contact: string status: string } + export interface DeploymentDetails { clientType: string team: string @@ -66,10 +67,7 @@ export interface ClientSecrets { } export interface BaseClientListFilter { - roleSearch: string - clientCredentials: boolean - authorisationCode: boolean - serviceClientType: boolean - personalClientType: boolean - blankClientType: boolean + roleSearch?: string + grantType?: GrantType + clientType?: ClientType[] } diff --git a/server/mappers/baseClientApi/listBaseClients.test.ts b/server/mappers/baseClientApi/listBaseClients.test.ts index a9197c5e..b61861eb 100644 --- a/server/mappers/baseClientApi/listBaseClients.test.ts +++ b/server/mappers/baseClientApi/listBaseClients.test.ts @@ -1,6 +1,9 @@ import { createMock } from '@golevelup/ts-jest' import { Request } from 'express' import { mapFilterToUrlQuery, mapListBaseClientRequest } from './listBaseClients' +import { filterFactory } from '../../testutils/factories' +import { GrantType } from '../../data/enums/grantType' +import { ClientType } from '../../data/enums/clientTypes' describe('Mappers for filtering base client list', () => { describe('mapListBaseClientRequest', () => { @@ -14,14 +17,7 @@ describe('Mappers for filtering base client list', () => { const filter = mapListBaseClientRequest(request) // THEN the filter defaults to include all values - const expected = { - roleSearch: '', - clientCredentials: true, - authorisationCode: true, - serviceClientType: true, - personalClientType: true, - blankClientType: true, - } + const expected = {} expect(filter).toEqual(expected) }) @@ -37,14 +33,8 @@ describe('Mappers for filtering base client list', () => { const filter = mapListBaseClientRequest(request) // THEN the filter defaults to include the roleSearch value - const expected = { - roleSearch: 'test role', - clientCredentials: true, - authorisationCode: true, - serviceClientType: true, - personalClientType: true, - blankClientType: true, - } + const expected = filterFactory.build({ roleSearch: 'test role' }) + expect(filter).toEqual(expected) }) @@ -60,37 +50,7 @@ describe('Mappers for filtering base client list', () => { const filter = mapListBaseClientRequest(request) // THEN the filter includes specified grantType only - const expected = { - roleSearch: '', - clientCredentials: true, - authorisationCode: false, - serviceClientType: true, - personalClientType: true, - blankClientType: true, - } - expect(filter).toEqual(expected) - }) - - it('maps multiple grantType parameters', async () => { - // GIVEN a request with a grantType parameter - const request = createMock({ - query: { - grantType: ['client-credentials', 'authorization-code'], - }, - }) - - // WHEN we map the request to a filter - const filter = mapListBaseClientRequest(request) - - // THEN the filter includes all specified grantTypes - const expected = { - roleSearch: '', - clientCredentials: true, - authorisationCode: true, - serviceClientType: true, - personalClientType: true, - blankClientType: true, - } + const expected = { grantType: GrantType.ClientCredentials } expect(filter).toEqual(expected) }) @@ -106,14 +66,9 @@ describe('Mappers for filtering base client list', () => { const filter = mapListBaseClientRequest(request) // THEN the filter includes specified grantType only - const expected = { - roleSearch: '', - clientCredentials: true, - authorisationCode: true, - serviceClientType: false, - personalClientType: true, - blankClientType: false, - } + const expected = filterFactory.build({ + clientType: [ClientType.Personal], + }) expect(filter).toEqual(expected) }) @@ -129,14 +84,9 @@ describe('Mappers for filtering base client list', () => { const filter = mapListBaseClientRequest(request) // THEN the filter includes all specified clientTypes - const expected = { - roleSearch: '', - clientCredentials: true, - authorisationCode: true, - serviceClientType: true, - personalClientType: true, - blankClientType: false, - } + const expected = filterFactory.build({ + clientType: [ClientType.Personal, ClientType.Service], + }) expect(filter).toEqual(expected) }) }) @@ -144,14 +94,7 @@ describe('Mappers for filtering base client list', () => { describe('mapFilterToUrlQuery', () => { it('maps to an empty string when the filter is empty', async () => { // GIVEN an empty filter - const filter = { - roleSearch: '', - clientCredentials: true, - authorisationCode: true, - serviceClientType: true, - personalClientType: true, - blankClientType: true, - } + const filter = {} // WHEN we map the filter to a query string const query = mapFilterToUrlQuery(filter) @@ -162,14 +105,7 @@ describe('Mappers for filtering base client list', () => { it('maps roleSearch to role', async () => { // GIVEN a filter with a roleSearch - const filter = { - roleSearch: 'test', - clientCredentials: true, - authorisationCode: true, - serviceClientType: true, - personalClientType: true, - blankClientType: true, - } + const filter = filterFactory.build({ roleSearch: 'test' }) // WHEN we map the filter to a query string const query = mapFilterToUrlQuery(filter) @@ -180,14 +116,7 @@ describe('Mappers for filtering base client list', () => { it('maps roleSearch to role with encoded characters', async () => { // GIVEN a filter with a roleSearch - const filter = { - roleSearch: 'test role', - clientCredentials: true, - authorisationCode: true, - serviceClientType: true, - personalClientType: true, - blankClientType: true, - } + const filter = filterFactory.build({ roleSearch: 'test role' }) // WHEN we map the filter to a query string const query = mapFilterToUrlQuery(filter) @@ -198,14 +127,9 @@ describe('Mappers for filtering base client list', () => { it('maps grantType parameters', async () => { // GIVEN a filter with a grantType parameter - const filter = { - roleSearch: '', - clientCredentials: true, - authorisationCode: false, - serviceClientType: true, - personalClientType: true, - blankClientType: true, - } + const filter = filterFactory.build({ + grantType: GrantType.ClientCredentials, + }) // WHEN we map the filter to a query string const query = mapFilterToUrlQuery(filter) @@ -216,14 +140,9 @@ describe('Mappers for filtering base client list', () => { it('maps clientType parameters', async () => { // GIVEN a filter with a client parameter - const filter = { - roleSearch: '', - clientCredentials: true, - authorisationCode: true, - serviceClientType: false, - personalClientType: true, - blankClientType: false, - } + const filter = filterFactory.build({ + clientType: [ClientType.Personal], + }) // WHEN we map the filter to a query string const query = mapFilterToUrlQuery(filter) @@ -234,38 +153,30 @@ describe('Mappers for filtering base client list', () => { it('maps multiple clientType parameters', async () => { // GIVEN a filter with a client parameter - const filter = { - roleSearch: '', - clientCredentials: true, - authorisationCode: true, - serviceClientType: true, - personalClientType: true, - blankClientType: false, - } + const filter = filterFactory.build({ + clientType: [ClientType.Service, ClientType.Personal], + }) // WHEN we map the filter to a query string const query = mapFilterToUrlQuery(filter) // THEN the query includes all specified clientTypes - expect(query).toEqual('clientType=personal&clientType=service') + expect(query).toEqual('clientType=service&clientType=personal') }) it('maps all parameters', async () => { // GIVEN a filter with a client parameter - const filter = { + const filter = filterFactory.build({ roleSearch: 'test role', - clientCredentials: true, - authorisationCode: false, - serviceClientType: true, - personalClientType: true, - blankClientType: false, - } + grantType: GrantType.ClientCredentials, + clientType: [ClientType.Service, ClientType.Personal], + }) // WHEN we map the filter to a query string const query = mapFilterToUrlQuery(filter) // THEN the query includes all specified clientTypes - expect(query).toEqual('role=test%20role&grantType=client-credentials&clientType=personal&clientType=service') + expect(query).toEqual('role=test%20role&grantType=client-credentials&clientType=service&clientType=personal') }) }) }) diff --git a/server/mappers/baseClientApi/listBaseClients.ts b/server/mappers/baseClientApi/listBaseClients.ts index c0bef7e6..2d8883f6 100644 --- a/server/mappers/baseClientApi/listBaseClients.ts +++ b/server/mappers/baseClientApi/listBaseClients.ts @@ -2,26 +2,28 @@ import { Request } from 'express' import { ListBaseClientsResponse } from '../../interfaces/baseClientApi/baseClientResponse' import { BaseClient, BaseClientListFilter } from '../../interfaces/baseClientApi/baseClient' import { kebab, multiSeparatorSplit, snake } from '../../utils/utils' -import { GrantTypes } from '../../data/enums/grantTypes' -import { ClientType } from '../../data/enums/clientTypes' +import { toClientType } from '../../data/enums/clientTypes' +import { toGrantType } from '../../data/enums/grantType' export const mapListBaseClientRequest = (request: Request): BaseClientListFilter => { const asJson = JSON.stringify(request.query) const data = asJson ? JSON.parse(asJson) : {} - const grantTypes = mapQueryList(data.grantType, [GrantTypes.ClientCredentials, GrantTypes.AuthorizationCode]).map( - snake, - ) - const clientTypes = mapQueryList(data.clientType, [ClientType.Personal, ClientType.Service, 'blank']).map(snake) - - return { - roleSearch: data.role ? data.role.trim() : '', - clientCredentials: grantTypes.includes(GrantTypes.ClientCredentials), - authorisationCode: grantTypes.includes(GrantTypes.AuthorizationCode), - serviceClientType: clientTypes.includes(ClientType.Service), - personalClientType: clientTypes.includes(ClientType.Personal), - blankClientType: clientTypes.includes('blank'), + const filter: BaseClientListFilter = {} + if (data.role) { + filter.roleSearch = data.role.trim() + } + if (data.grantType) { + filter.grantType = toGrantType(data.grantType) + } + if (data.clientType) { + if (Array.isArray(data.clientType)) { + filter.clientType = data.clientType.map(toClientType) + } else { + filter.clientType = [toClientType(data.clientType)] + } } + return filter } export const mapFilterToUrlQuery = (filter: BaseClientListFilter): string => { @@ -29,36 +31,20 @@ export const mapFilterToUrlQuery = (filter: BaseClientListFilter): string => { if (filter.roleSearch) { urlQuery += `role=${encodeURIComponent(filter.roleSearch)}&` } - if (!(filter.clientCredentials && filter.authorisationCode)) { - if (filter.clientCredentials) { - urlQuery += `grantType=${kebab(GrantTypes.ClientCredentials)}&` - } - if (filter.authorisationCode) { - urlQuery += `grantType=${kebab(GrantTypes.AuthorizationCode)}&` - } + if (filter.grantType) { + urlQuery += `grantType=${kebab(filter.grantType)}&` } - if (!(filter.personalClientType && filter.serviceClientType && filter.blankClientType)) { - if (filter.personalClientType) { - urlQuery += `clientType=${kebab(ClientType.Personal)}&` - } - if (filter.serviceClientType) { - urlQuery += `clientType=${kebab(ClientType.Service)}&` - } - if (filter.blankClientType) { - urlQuery += `clientType=blank&` - } + if (filter.clientType) { + filter.clientType.forEach(clientType => { + urlQuery += `clientType=${kebab(clientType)}&` + }) } + if (urlQuery.endsWith('&')) { urlQuery = urlQuery.slice(0, -1) } - return urlQuery -} -const mapQueryList = (value: string | string[], defaults: string[]): string[] => { - if (Array.isArray(value)) { - return value - } - return value ? [value] : defaults + return urlQuery } export default (response: ListBaseClientsResponse): BaseClient[] => { diff --git a/server/mappers/forms/mapFilterForm.test.ts b/server/mappers/forms/mapFilterForm.test.ts index 9698cf88..e436f997 100644 --- a/server/mappers/forms/mapFilterForm.test.ts +++ b/server/mappers/forms/mapFilterForm.test.ts @@ -2,6 +2,8 @@ import type { Request } from 'express' import { createMock } from '@golevelup/ts-jest' import mapFilterForm from './mapFilterForm' import { BaseClientListFilter } from '../../interfaces/baseClientApi/baseClient' +import { GrantType } from '../../data/enums/grantType' +import { ClientType } from '../../data/enums/clientTypes' const formRequest = (form: Record) => { return createMock({ body: form }) @@ -20,15 +22,7 @@ describe('mapFilterForm', () => { }) }) - describe('grant checkbox', () => { - it('processes undefined', () => { - const request = formRequest({}) - - const result: BaseClientListFilter = mapFilterForm(request) - - expect(result.authorisationCode).toBeFalsy() - expect(result.clientCredentials).toBeFalsy() - }) + describe('grant radios', () => { it('processes single string', () => { const request = formRequest({ grantType: 'client_credentials', @@ -36,52 +30,50 @@ describe('mapFilterForm', () => { const result: BaseClientListFilter = mapFilterForm(request) - expect(result.authorisationCode).toBeFalsy() - expect(result.clientCredentials).toBeTruthy() + expect(result.grantType).toEqual(GrantType.ClientCredentials) }) - it('processes array', () => { + }) + + describe('client type radios', () => { + it('parses filter on but no selection as select all', () => { const request = formRequest({ - grantType: ['client_credentials', 'authorization_code'], + filterClientType: 'clientFilter', }) const result: BaseClientListFilter = mapFilterForm(request) - expect(result.authorisationCode).toBeTruthy() - expect(result.clientCredentials).toBeTruthy() + expect(result.clientType).toBeUndefined() }) - }) - - describe('client type checkbox', () => { - it('processes undefined', () => { - const request = formRequest({}) + it('parses filter on with all selected as select all', () => { + const request = formRequest({ + filterClientType: 'clientFilter', + clientType: ['personal', 'service', 'blank'], + }) const result: BaseClientListFilter = mapFilterForm(request) - expect(result.personalClientType).toBeFalsy() - expect(result.serviceClientType).toBeFalsy() - expect(result.blankClientType).toBeFalsy() + expect(result.clientType).toBeUndefined() }) + it('processes single string', () => { const request = formRequest({ + filterClientType: 'clientFilter', clientType: 'personal', }) const result: BaseClientListFilter = mapFilterForm(request) - expect(result.personalClientType).toBeTruthy() - expect(result.serviceClientType).toBeFalsy() - expect(result.blankClientType).toBeFalsy() + expect(result.clientType).toEqual([ClientType.Personal]) }) it('processes array', () => { const request = formRequest({ + filterClientType: 'clientFilter', clientType: ['personal', 'service'], }) const result: BaseClientListFilter = mapFilterForm(request) - expect(result.personalClientType).toBeTruthy() - expect(result.serviceClientType).toBeTruthy() - expect(result.blankClientType).toBeFalsy() + expect(result.clientType).toEqual([ClientType.Personal, ClientType.Service]) }) }) }) diff --git a/server/mappers/forms/mapFilterForm.ts b/server/mappers/forms/mapFilterForm.ts index 1e643d8c..ea09d3c3 100644 --- a/server/mappers/forms/mapFilterForm.ts +++ b/server/mappers/forms/mapFilterForm.ts @@ -1,24 +1,32 @@ import { Request } from 'express' import { BaseClientListFilter } from '../../interfaces/baseClientApi/baseClient' -import { GrantTypes } from '../../data/enums/grantTypes' -import { ClientType } from '../../data/enums/clientTypes' +import { toGrantType } from '../../data/enums/grantType' +import { toClientType } from '../../data/enums/clientTypes' import { snake } from '../../utils/utils' export default (request: Request): BaseClientListFilter => { // valid days is calculated from expiry date const data = request.body - const grantTypes = mapCheckboxes(data.grantType).map(snake) - const clientTypes = mapCheckboxes(data.clientType).map(snake) + const filter: BaseClientListFilter = {} + if (data.role) { + filter.roleSearch = data.role.trim() + } - return { - roleSearch: data.role ? data.role.trim() : '', - clientCredentials: grantTypes.includes(GrantTypes.ClientCredentials), - authorisationCode: grantTypes.includes(GrantTypes.AuthorizationCode), - serviceClientType: clientTypes.includes(ClientType.Service), - personalClientType: clientTypes.includes(ClientType.Personal), - blankClientType: clientTypes.includes('blank'), + if (data.grantType && data.grantType !== 'all') { + filter.grantType = toGrantType(snake(data.grantType)) } + + if (data.filterClientType === 'clientFilter') { + const clientTypes = mapCheckboxes(data.clientType).map(snake).map(toClientType) + + // if no or all client types are selected, we don't want to filter by client type + if (clientTypes.length > 0 && clientTypes.length < 3) { + filter.clientType = clientTypes + } + } + + return filter } const mapCheckboxes = (value: string | string[]): string[] => { diff --git a/server/testutils/factories/filter.ts b/server/testutils/factories/filter.ts index 15af5294..e45930ca 100644 --- a/server/testutils/factories/filter.ts +++ b/server/testutils/factories/filter.ts @@ -1,11 +1,4 @@ import { Factory } from 'fishery' import { BaseClientListFilter } from '../../interfaces/baseClientApi/baseClient' -export default Factory.define(() => ({ - roleSearch: '', - clientCredentials: true, - authorisationCode: true, - serviceClientType: true, - personalClientType: true, - blankClientType: true, -})) +export default Factory.define(() => ({})) diff --git a/server/views/pages/base-clients.njk b/server/views/pages/base-clients.njk index 5361f8b2..7d9556c5 100644 --- a/server/views/pages/base-clients.njk +++ b/server/views/pages/base-clients.njk @@ -22,6 +22,7 @@ {%- from "govuk/components/table/macro.njk" import govukTable -%} {%- from "moj/components/filter/macro.njk" import mojFilter -%} {%- from "moj/components/button-menu/macro.njk" import mojButtonMenu -%} +{% from "govuk/components/radios/macro.njk" import govukRadios %} {% set filterOptionsHtml %} @@ -39,55 +40,79 @@ value: presenter.filter.roleSearch }) }} - {{ govukCheckboxes({ - idPrefix: 'grant-type', - name: 'grantType', - classes: "govuk-checkboxes--small", + {{ govukRadios({ + name: "grantType", + classes: "govuk-radios--small", fieldset: { legend: { - text: 'Grant type', - classes: 'govuk-fieldset__legend--m' + text: "Grant type", + isPageHeading: false, + classes: "govuk-fieldset__legend--m" } }, items: [ { - value: 'client-credentials', - text: 'Client credentials', - checked: presenter.filter.clientCredentials + value: "all", + text: "All", + checked: 'grantType' not in presenter.filter }, { - value: 'authorization-code', - text: 'Authorization code', - checked: presenter.filter.authorisationCode + value: "client-credentials", + text: "Client credentials", + checked: presenter.filter.grantType === "client_credentials" + }, + { + value: "authorization-code", + text: "Authorization code", + checked: presenter.filter.grantType === "authorization_code" } ] }) }} - {{ govukCheckboxes({ - idPrefix: 'client-type', - name: 'clientType', - classes: "govuk-checkboxes--small", + {{ govukRadios({ + name: "filterClientType", + classes: "govuk-radios--small", fieldset: { legend: { - text: 'Client type', - classes: 'govuk-fieldset__legend--m' + text: "Client type", + isPageHeading: false, + classes: "govuk-fieldset__legend--m" } }, items: [ { - value: 'service', - text: 'Service', - checked: presenter.filter.serviceClientType - }, - { - value: 'personal', - text: 'Personal', - checked: presenter.filter.personalClientType + value: "all", + text: "All", + checked: 'clientType' not in presenter.filter }, { - value: 'blank', - text: '[blank]', - checked: presenter.filter.blankClientType + value: "clientFilter", + text: "Filter", + checked: 'clientType' in presenter.filter, + conditional: { + html: govukCheckboxes({ + idPrefix: 'client-type', + name: 'clientType', + classes: "govuk-checkboxes--small", + items: [ + { + value: 'service', + text: 'Service', + checked: 'clientType' in presenter.filter and 'service' in presenter.filter.clientType + }, + { + value: 'personal', + text: 'Personal', + checked: 'clientType' in presenter.filter and 'personal' in presenter.filter.clientType + }, + { + value: 'blank', + text: '[blank]', + checked: 'clientType' in presenter.filter and 'blank' in presenter.filter.clientType + } + ] + }) + } } ] }) }} diff --git a/server/views/partials/list_filter.njk b/server/views/partials/list_filter.njk deleted file mode 100644 index 3e1a8f23..00000000 --- a/server/views/partials/list_filter.njk +++ /dev/null @@ -1,83 +0,0 @@ -{% call govukFieldset({ - legend: { - text: "Filter clients", - classes: "govuk-fieldset__legend--l", - isPageHeading: false - } -}) %} - -
-
- {{ govukInput({ - label: { - text: "Role" - }, - id: "filter-role", - name: "filterRole" - }) }} -
- -
- {{ govukSelect({ - id: "filter-grant-type", - name: "filterGrantType", - label: { - text: "Grant type" - }, - items: [ - { - value: "all", - text: "All", - selected: "true" - }, - { - value: "client-credentials", - text: "Client creds" - }, - { - value: "authorization-code", - text: "Auth code" - } - ] - }) }} - -
- -
- {{ govukSelect({ - id: "filter-client-type", - name: "filterClientType", - label: { - text: "Client type" - }, - items: [ - { - value: "all", - text: "All", - selected: "true" - }, - { - value: "service", - text: "Service" - }, - { - value: "personal", - text: "Personal" - } - ] - }) }} -
- - -
- {{ govukLabel({ - text: "." - }) }} - {{ govukButton({ - text: "Search" - }) }} -
- -
- -{% endcall %} \ No newline at end of file diff --git a/server/views/presenters/listBaseClientsPresenter.test.ts b/server/views/presenters/listBaseClientsPresenter.test.ts index 42073a08..43b7de14 100644 --- a/server/views/presenters/listBaseClientsPresenter.test.ts +++ b/server/views/presenters/listBaseClientsPresenter.test.ts @@ -1,7 +1,7 @@ import { BaseClient } from '../../interfaces/baseClientApi/baseClient' import { baseClientFactory, filterFactory } from '../../testutils/factories' import listBaseClientsPresenter, { filterBaseClient } from './listBaseClientsPresenter' -import { GrantTypes } from '../../data/enums/grantTypes' +import { GrantType } from '../../data/enums/grantType' import { ClientType } from '../../data/enums/clientTypes' let baseClients: BaseClient[] @@ -109,28 +109,32 @@ describe('listBaseClientsPresenter', () => { }) describe('by grant type', () => { - const clientCredentialsBaseClient = baseClientFactory.build({ grantType: GrantTypes.ClientCredentials }) - const authCodeBaseClient = baseClientFactory.build({ grantType: GrantTypes.AuthorizationCode }) + const clientCredentialsBaseClient = baseClientFactory.build({ grantType: GrantType.ClientCredentials }) + const authCodeBaseClient = baseClientFactory.build({ grantType: GrantType.AuthorizationCode }) it('defaults to matching all types', () => { - const filter = filterFactory.build() + const filter = filterFactory.build({}) expect(filterBaseClient(clientCredentialsBaseClient, filter)).toBeTruthy() expect(filterBaseClient(authCodeBaseClient, filter)).toBeTruthy() }) - it('can filter out only client credentials', () => { - const filter = filterFactory.build({ clientCredentials: false }) + it('can filter to client credentials only', () => { + const filter = filterFactory.build({ + grantType: GrantType.ClientCredentials, + }) - expect(filterBaseClient(clientCredentialsBaseClient, filter)).toBeFalsy() - expect(filterBaseClient(authCodeBaseClient, filter)).toBeTruthy() + expect(filterBaseClient(clientCredentialsBaseClient, filter)).toBeTruthy() + expect(filterBaseClient(authCodeBaseClient, filter)).toBeFalsy() }) - it('can filter out only auth code', () => { - const filter = filterFactory.build({ authorisationCode: false }) + it('can filter to auth code only', () => { + const filter = filterFactory.build({ + grantType: GrantType.AuthorizationCode, + }) - expect(filterBaseClient(clientCredentialsBaseClient, filter)).toBeTruthy() - expect(filterBaseClient(authCodeBaseClient, filter)).toBeFalsy() + expect(filterBaseClient(clientCredentialsBaseClient, filter)).toBeFalsy() + expect(filterBaseClient(authCodeBaseClient, filter)).toBeTruthy() }) }) @@ -147,28 +151,36 @@ describe('listBaseClientsPresenter', () => { expect(filterBaseClient(blankBaseClient, filter)).toBeTruthy() }) - it('can filter out service clients', () => { - const filter = filterFactory.build({ serviceClientType: false }) + it('can filter to only service clients', () => { + const filter = filterFactory.build({ clientType: [ClientType.Service] }) + + expect(filterBaseClient(serviceBaseClient, filter)).toBeTruthy() + expect(filterBaseClient(personalBaseClient, filter)).toBeFalsy() + expect(filterBaseClient(blankBaseClient, filter)).toBeFalsy() + }) + + it('can filter to only personal clients', () => { + const filter = filterFactory.build({ clientType: [ClientType.Personal] }) expect(filterBaseClient(serviceBaseClient, filter)).toBeFalsy() expect(filterBaseClient(personalBaseClient, filter)).toBeTruthy() - expect(filterBaseClient(blankBaseClient, filter)).toBeTruthy() + expect(filterBaseClient(blankBaseClient, filter)).toBeFalsy() }) - it('can filter out personal clients', () => { - const filter = filterFactory.build({ personalClientType: false }) + it('can filter to only blank clients', () => { + const filter = filterFactory.build({ clientType: [ClientType.Blank] }) - expect(filterBaseClient(serviceBaseClient, filter)).toBeTruthy() + expect(filterBaseClient(serviceBaseClient, filter)).toBeFalsy() expect(filterBaseClient(personalBaseClient, filter)).toBeFalsy() expect(filterBaseClient(blankBaseClient, filter)).toBeTruthy() }) - it('can filter out blank clients', () => { - const filter = filterFactory.build({ blankClientType: false }) + it('can filter to multiple client types', () => { + const filter = filterFactory.build({ clientType: [ClientType.Personal, ClientType.Blank] }) - expect(filterBaseClient(serviceBaseClient, filter)).toBeTruthy() + expect(filterBaseClient(serviceBaseClient, filter)).toBeFalsy() expect(filterBaseClient(personalBaseClient, filter)).toBeTruthy() - expect(filterBaseClient(blankBaseClient, filter)).toBeFalsy() + expect(filterBaseClient(blankBaseClient, filter)).toBeTruthy() }) }) }) @@ -213,8 +225,8 @@ describe('listBaseClientsPresenter', () => { expect(selectedFilterCategories[0].items[0].text).toEqual('ONE') }) - it('has visible grant type category if either of the grant types are deselected', () => { - const filter = filterFactory.build({ clientCredentials: false }) + it('has visible grant type category if non-all grantType category selected', () => { + const filter = filterFactory.build({ grantType: GrantType.AuthorizationCode }) const { selectedFilterCategories } = listBaseClientsPresenter(baseClients, filter) expect(selectedFilterCategories).toHaveLength(1) @@ -222,37 +234,37 @@ describe('listBaseClientsPresenter', () => { expect(selectedFilterCategories[0].items[0].text).toEqual('Authorisation code') }) - it('has no grant type category if all grant types are deselected', () => { - const filter = filterFactory.build({ clientCredentials: false, authorisationCode: false }) - const { selectedFilterCategories } = listBaseClientsPresenter(baseClients, filter) - - expect(selectedFilterCategories).toHaveLength(0) - }) - it('has visible client type category if single client type is selected', () => { - const filter = filterFactory.build({ serviceClientType: false, personalClientType: false }) + const filter = filterFactory.build({ clientType: [ClientType.Personal] }) const { selectedFilterCategories } = listBaseClientsPresenter(baseClients, filter) expect(selectedFilterCategories).toHaveLength(1) expect(selectedFilterCategories[0].heading.text).toEqual('Client type') - expect(selectedFilterCategories[0].items[0].text).toEqual('Blank') + expect(selectedFilterCategories[0].items[0].text).toEqual('Personal') }) it('has two client type categories if single client type is selected', () => { - const filter = filterFactory.build({ serviceClientType: false }) + const filter = filterFactory.build({ clientType: [ClientType.Personal, ClientType.Service] }) const { selectedFilterCategories } = listBaseClientsPresenter(baseClients, filter) expect(selectedFilterCategories).toHaveLength(1) expect(selectedFilterCategories[0].heading.text).toEqual('Client type') expect(selectedFilterCategories[0].items[0].text).toEqual('Personal') - expect(selectedFilterCategories[0].items[1].text).toEqual('Blank') + expect(selectedFilterCategories[0].items[1].text).toEqual('Service') }) it('has no client type category if no client type is selected', () => { const filter = filterFactory.build({ - blankClientType: false, - personalClientType: false, - serviceClientType: false, + clientType: [], + }) + const { selectedFilterCategories } = listBaseClientsPresenter(baseClients, filter) + + expect(selectedFilterCategories).toHaveLength(0) + }) + + it('has no client type category if all client types are selected', () => { + const filter = filterFactory.build({ + clientType: [ClientType.Personal, ClientType.Service, ClientType.Blank], }) const { selectedFilterCategories } = listBaseClientsPresenter(baseClients, filter) @@ -262,8 +274,8 @@ describe('listBaseClientsPresenter', () => { it('can have complex filters with multiple categories', () => { const filter = filterFactory.build({ roleSearch: 'ONE', - clientCredentials: false, - serviceClientType: false, + grantType: GrantType.AuthorizationCode, + clientType: [ClientType.Personal, ClientType.Blank], }) const { selectedFilterCategories } = listBaseClientsPresenter(baseClients, filter) @@ -295,8 +307,8 @@ describe('listBaseClientsPresenter', () => { // current URL is /?role=ONE&grantType=authorization-code&clientType=personal&clientType=blank const compoundFilter = filterFactory.build({ roleSearch: 'ONE', - clientCredentials: false, - serviceClientType: false, + grantType: GrantType.AuthorizationCode, + clientType: [ClientType.Personal, ClientType.Blank], }) const presenter = listBaseClientsPresenter(baseClients, compoundFilter) diff --git a/server/views/presenters/listBaseClientsPresenter.ts b/server/views/presenters/listBaseClientsPresenter.ts index 5a4a97b6..acbe4453 100644 --- a/server/views/presenters/listBaseClientsPresenter.ts +++ b/server/views/presenters/listBaseClientsPresenter.ts @@ -1,7 +1,7 @@ import { BaseClient, BaseClientListFilter } from '../../interfaces/baseClientApi/baseClient' -import { convertToTitleCase, dateFormatFromString, snake } from '../../utils/utils' -import { GrantTypes } from '../../data/enums/grantTypes' -import { ClientType } from '../../data/enums/clientTypes' +import { convertToTitleCase, dateFormatFromString } from '../../utils/utils' +import { GrantType, toGrantType } from '../../data/enums/grantType' +import { ClientType, toClientType } from '../../data/enums/clientTypes' import { mapFilterToUrlQuery } from '../../mappers/baseClientApi/listBaseClients' const indexTableHead = () => { @@ -103,134 +103,157 @@ const filterItems = (data: BaseClient[], filter?: BaseClientListFilter) => { return filter ? data.filter(item => filterBaseClient(item, filter)) : data } -export const filterBaseClient = (baseClient: BaseClient, filter: BaseClientListFilter) => { - if (filter.roleSearch) { +const filterByRoleSearch = (baseClient: BaseClient, roleSearch: string): boolean => { + if (roleSearch) { const roles = baseClient.clientCredentials.authorities.join(' ').toLowerCase() - const roleSearch = filter.roleSearch.toLowerCase().trim() - if (roles.includes(roleSearch) === false) { - return false - } + const roleSearchLower = roleSearch.toLowerCase().trim() + return roles.includes(roleSearchLower) } + return true +} - const grantType = baseClient.grantType ? snake(baseClient.grantType) : '' +const filterByGrantType = (baseClient: BaseClient, grantTypeFilter: GrantType | undefined): boolean => { + const grantType = baseClient.grantType ? toGrantType(baseClient.grantType) : null + return grantTypeFilter ? grantType === grantTypeFilter : true +} + +const filterByClientType = (baseClient: BaseClient, clientTypeFilter: ClientType[] | undefined): boolean => { const clientType = - baseClient.deployment && baseClient.deployment.clientType ? snake(baseClient.deployment.clientType) : '' + baseClient.deployment && baseClient.deployment.clientType + ? toClientType(baseClient.deployment.clientType) + : ClientType.Blank + return clientTypeFilter ? clientTypeFilter.includes(clientType) : true +} - if (grantType === GrantTypes.ClientCredentials && !filter.clientCredentials) { - return false +export const filterBaseClient = (baseClient: BaseClient, filter: BaseClientListFilter): boolean => { + return ( + filterByRoleSearch(baseClient, filter.roleSearch) && + filterByGrantType(baseClient, filter.grantType) && + filterByClientType(baseClient, filter.clientType) + ) +} + +type SelectedFilterCategory = { + heading: { text: string } + items: { href: string; text: string }[] +} + +const createRoleSearchCategory = (filter: BaseClientListFilter): SelectedFilterCategory[] => { + return filter.roleSearch + ? [ + { + heading: { text: 'Role' }, + items: [{ href: removeFilterLink(filter, 'roleSearch'), text: filter.roleSearch }], + }, + ] + : [] +} + +const createGrantTypeCategory = (filter: BaseClientListFilter): SelectedFilterCategory[] => { + if (!filter.grantType) return [] + + const grantTypesCategory: SelectedFilterCategory = { + heading: { text: 'Grant type' }, + items: [], } - if (grantType === GrantTypes.AuthorizationCode && !filter.authorisationCode) { - return false + if (filter.grantType === GrantType.ClientCredentials) { + grantTypesCategory.items.push({ href: removeFilterLink(filter, 'clientCredentials'), text: 'Client credentials' }) } - if (clientType === ClientType.Personal && !filter.personalClientType) { - return false + if (filter.grantType === GrantType.AuthorizationCode) { + grantTypesCategory.items.push({ href: removeFilterLink(filter, 'authorisationCode'), text: 'Authorisation code' }) } - if (clientType === ClientType.Service && !filter.serviceClientType) { - return false + + return [grantTypesCategory] +} + +const createClientTypeCategory = (filter: BaseClientListFilter): SelectedFilterCategory[] => { + if (!filter.clientType) return [] + + const clientTypeCategory: SelectedFilterCategory = { + heading: { text: 'Client type' }, + items: [], } - if (clientType === '' && !filter.blankClientType) { - return false + if (filter.clientType.includes(ClientType.Personal)) { + clientTypeCategory.items.push({ href: removeFilterLink(filter, 'personalClientType'), text: 'Personal' }) } - return true + if (filter.clientType.includes(ClientType.Service)) { + clientTypeCategory.items.push({ href: removeFilterLink(filter, 'serviceClientType'), text: 'Service' }) + } + + if (filter.clientType.includes(ClientType.Blank)) { + clientTypeCategory.items.push({ href: removeFilterLink(filter, 'blankClientType'), text: 'Blank' }) + } + + if (clientTypeCategory.items.length > 0 && clientTypeCategory.items.length < 3) { + return [clientTypeCategory] + } + return [] } -type SelectedFilterCategory = { - heading: { text: string } - items: { href: string; text: string }[] +const getSelectedFilterCategories = (filter?: BaseClientListFilter): SelectedFilterCategory[] => { + if (!filter) return [] + return [...createRoleSearchCategory(filter), ...createGrantTypeCategory(filter), ...createClientTypeCategory(filter)] } -const getSelectedFilterCategories = (filter: BaseClientListFilter): SelectedFilterCategory[] => { - const categories: SelectedFilterCategory[] = [] - if (filter.roleSearch) { - categories.push({ - heading: { - text: 'Role', - }, - items: [{ href: removeFilterLink(filter, 'roleSearch'), text: filter.roleSearch }], - }) +const removeRoleSearchFilter = (filter: BaseClientListFilter, filterToRemove: string): BaseClientListFilter => { + if (filter.roleSearch && filterToRemove !== 'roleSearch') { + return { roleSearch: filter.roleSearch } } + return {} +} - if (filter.clientCredentials === false || filter.authorisationCode === false) { - const grantTypesCategory: SelectedFilterCategory = { - heading: { - text: 'Grant type', - }, - items: [], - } - if (filter.clientCredentials) { - grantTypesCategory.items.push({ href: removeFilterLink(filter, 'clientCredentials'), text: 'Client credentials' }) - } - if (filter.authorisationCode) { - grantTypesCategory.items.push({ href: removeFilterLink(filter, 'authorisationCode'), text: 'Authorisation code' }) - } - if (grantTypesCategory.items.length > 0) { - categories.push(grantTypesCategory) - } +const removeGrantTypeFilter = (filter: BaseClientListFilter, filterToRemove: string): BaseClientListFilter => { + if (filter.grantType && !['clientCredentials', 'authorisationCode'].includes(filterToRemove)) { + return { grantType: filter.grantType } } + return {} +} - if (filter.personalClientType === false || filter.serviceClientType === false || filter.blankClientType === false) { - const clientTypeCategory: SelectedFilterCategory = { - heading: { - text: 'Client type', - }, - items: [], - } - if (filter.personalClientType) { - clientTypeCategory.items.push({ href: removeFilterLink(filter, 'personalClientType'), text: 'Personal' }) +const removeClientTypeFilter = (filter: BaseClientListFilter, filterToRemove: string): BaseClientListFilter => { + if (filter.clientType) { + let clients = filter.clientType + if (filterToRemove === 'personalClientType') { + clients = clients.filter(client => client !== ClientType.Personal) } - if (filter.serviceClientType) { - clientTypeCategory.items.push({ href: removeFilterLink(filter, 'serviceClientType'), text: 'Service' }) + if (filterToRemove === 'serviceClientType') { + clients = clients.filter(client => client !== ClientType.Service) } - if (filter.blankClientType) { - clientTypeCategory.items.push({ href: removeFilterLink(filter, 'blankClientType'), text: 'Blank' }) + if (filterToRemove === 'blankClientType') { + clients = clients.filter(client => client !== ClientType.Blank) } - if (clientTypeCategory.items.length > 0) { - categories.push(clientTypeCategory) + if (clients.length > 0 && clients.length < 3) { + return { clientType: clients } } } - - return categories + return {} } const removeFilterLink = (filter: BaseClientListFilter, filterToRemove: string): string => { - const newFilter: BaseClientListFilter = { ...filter } - if (filterToRemove === 'roleSearch') { - newFilter.roleSearch = '' - } else if (filterToRemove === 'clientCredentials') { - newFilter.clientCredentials = false - } else if (filterToRemove === 'authorisationCode') { - newFilter.authorisationCode = false - } else if (filterToRemove === 'personalClientType') { - newFilter.personalClientType = false - } else if (filterToRemove === 'serviceClientType') { - newFilter.serviceClientType = false - } else if (filterToRemove === 'blankClientType') { - newFilter.blankClientType = false + const newFilter: BaseClientListFilter = { + ...removeRoleSearchFilter(filter, filterToRemove), + ...removeGrantTypeFilter(filter, filterToRemove), + ...removeClientTypeFilter(filter, filterToRemove), } + const query = mapFilterToUrlQuery(newFilter) return query ? `/?${query}` : '/' } -export default (data: BaseClient[], filter?: BaseClientListFilter) => { - const defaultFilter: BaseClientListFilter = { - roleSearch: '', - clientCredentials: true, - authorisationCode: true, - serviceClientType: true, - personalClientType: true, - blankClientType: true, - } - const currentFilter = filter || defaultFilter +const showSelectedFilters = (filter?: BaseClientListFilter) => { + if (!filter) return false + return !(!filter.roleSearch && !filter.grantType && !filter.clientType) +} +export default (data: BaseClient[], filter?: BaseClientListFilter) => { return { tableHead: indexTableHead(), tableRows: indexTableRows(data, filter), - filter: currentFilter, - showSelectedFilters: JSON.stringify(currentFilter) !== JSON.stringify(defaultFilter), - selectedFilterCategories: getSelectedFilterCategories(currentFilter), + filter: filter || {}, + showSelectedFilters: showSelectedFilters(filter), + selectedFilterCategories: getSelectedFilterCategories(filter), } } From e6b96ffce0857c8eac67f0ee7d44d5a8d5f1bae1 Mon Sep 17 00:00:00 2001 From: thomasridd Date: Mon, 4 Mar 2024 16:21:03 +0000 Subject: [PATCH 8/8] update dependencies --- helm_deploy/hmpps-authorization/Chart.yaml | 2 +- package-lock.json | 289 +++++++++------------ package.json | 4 +- 3 files changed, 126 insertions(+), 169 deletions(-) diff --git a/helm_deploy/hmpps-authorization/Chart.yaml b/helm_deploy/hmpps-authorization/Chart.yaml index 1f361510..fa595583 100644 --- a/helm_deploy/hmpps-authorization/Chart.yaml +++ b/helm_deploy/hmpps-authorization/Chart.yaml @@ -8,5 +8,5 @@ dependencies: version: "2.9" repository: https://ministryofjustice.github.io/hmpps-helm-charts - name: generic-prometheus-alerts - version: "1.3" + version: "1.4" repository: https://ministryofjustice.github.io/hmpps-helm-charts diff --git a/package-lock.json b/package-lock.json index 15b692f9..66686d4e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -62,8 +62,8 @@ "@types/superagent": "^8.1.4", "@types/supertest": "^6.0.2", "@types/uuid": "^9.0.8", - "@typescript-eslint/eslint-plugin": "^7.0.1", - "@typescript-eslint/parser": "^7.0.1", + "@typescript-eslint/eslint-plugin": "^7.1.0", + "@typescript-eslint/parser": "^7.1.0", "audit-ci": "^6.6.1", "concurrently": "^8.2.2", "cookie-session": "^2.1.0", @@ -262,7 +262,7 @@ "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/client-sso": { + "node_modules/@aws-sdk/client-sso": { "version": "3.525.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.525.0.tgz", "integrity": "sha512-6KwGQWFoNLH1UupdWPFdKPfTgjSz1kN8/r8aCzuvvXBe4Pz+iDUZ6FEJzGWNc9AapjvZDNO1hs23slomM9rTaA==", @@ -310,7 +310,7 @@ "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/client-sso-oidc": { + "node_modules/@aws-sdk/client-sso-oidc": { "version": "3.525.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.525.0.tgz", "integrity": "sha512-zz13k/6RkjPSLmReSeGxd8wzGiiZa4Odr2Tv3wTcxClM4wOjD+zOgGv4Fe32b9AMqaueiCdjbvdu7AKcYxFA4A==", @@ -362,7 +362,7 @@ "@aws-sdk/credential-provider-node": "^3.525.0" } }, - "node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/client-sts": { + "node_modules/@aws-sdk/client-sts": { "version": "3.525.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.525.0.tgz", "integrity": "sha512-a8NUGRvO6rkfTZCbMaCsjDjLbERCwIUU9dIywFYcRgbFhkupJ7fSaZz3Het98U51M9ZbTEpaTa3fz0HaJv8VJw==", @@ -414,7 +414,7 @@ "@aws-sdk/credential-provider-node": "^3.525.0" } }, - "node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/core": { + "node_modules/@aws-sdk/core": { "version": "3.525.0", "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.525.0.tgz", "integrity": "sha512-E3LtEtMWCriQOFZpVKpLYzbdw/v2PAOEAMhn2VRRZ1g0/g1TXzQrfhEU2yd8l/vQEJaCJ82ooGGg7YECviBUxA==", @@ -430,7 +430,7 @@ "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/credential-provider-env": { + "node_modules/@aws-sdk/credential-provider-env": { "version": "3.523.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.523.0.tgz", "integrity": "sha512-Y6DWdH6/OuMDoNKVzZlNeBc6f1Yjk1lYMjANKpIhMbkRCvLJw/PYZKOZa8WpXbTYdgg9XLjKybnLIb3ww3uuzA==", @@ -444,7 +444,26 @@ "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/credential-provider-ini": { + "node_modules/@aws-sdk/credential-provider-http": { + "version": "3.525.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.525.0.tgz", + "integrity": "sha512-RNWQGuSBQZhl3iqklOslUEfQ4br1V3DCPboMpeqFtddUWJV3m2u2extFur9/4Uy+1EHVF120IwZUKtd8dF+ibw==", + "dependencies": { + "@aws-sdk/types": "3.523.0", + "@smithy/fetch-http-handler": "^2.4.3", + "@smithy/node-http-handler": "^2.4.1", + "@smithy/property-provider": "^2.1.3", + "@smithy/protocol-http": "^3.2.1", + "@smithy/smithy-client": "^2.4.2", + "@smithy/types": "^2.10.1", + "@smithy/util-stream": "^2.1.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini": { "version": "3.525.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.525.0.tgz", "integrity": "sha512-JDnccfK5JRb9jcgpc9lirL9PyCwGIqY0nKdw3LlX5WL5vTpTG4E1q7rLAlpNh7/tFD1n66Itarfv2tsyHMIqCw==", @@ -465,7 +484,7 @@ "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/credential-provider-node": { + "node_modules/@aws-sdk/credential-provider-node": { "version": "3.525.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.525.0.tgz", "integrity": "sha512-RJXlO8goGXpnoHQAyrCcJ0QtWEOFa34LSbfdqBIjQX/fwnjUuEmiGdXTV3AZmwYQ7juk49tfBneHbtOP3AGqsQ==", @@ -487,7 +506,7 @@ "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/credential-provider-process": { + "node_modules/@aws-sdk/credential-provider-process": { "version": "3.523.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.523.0.tgz", "integrity": "sha512-f0LP9KlFmMvPWdKeUKYlZ6FkQAECUeZMmISsv6NKtvPCI9e4O4cLTeR09telwDK8P0HrgcRuZfXM7E30m8re0Q==", @@ -502,7 +521,7 @@ "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/credential-provider-sso": { + "node_modules/@aws-sdk/credential-provider-sso": { "version": "3.525.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.525.0.tgz", "integrity": "sha512-7V7ybtufxdD3plxeIeB6aqHZeFIUlAyPphXIUgXrGY10iNcosL970rQPBeggsohe4gCM6UvY2TfMeEcr+ZE8FA==", @@ -519,7 +538,7 @@ "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/credential-provider-web-identity": { + "node_modules/@aws-sdk/credential-provider-web-identity": { "version": "3.525.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.525.0.tgz", "integrity": "sha512-sAukOjR1oKb2JXG4nPpuBFpSwGUhrrY17PG/xbTy8NAoLLhrqRwnErcLfdTfmj6tH+3094k6ws/Sh8a35ae7fA==", @@ -534,7 +553,7 @@ "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/middleware-host-header": { + "node_modules/@aws-sdk/middleware-host-header": { "version": "3.523.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.523.0.tgz", "integrity": "sha512-4g3q7Ta9sdD9TMUuohBAkbx/e3I/juTqfKi7TPgP+8jxcYX72MOsgemAMHuP6CX27eyj4dpvjH+w4SIVDiDSmg==", @@ -548,7 +567,7 @@ "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/middleware-logger": { + "node_modules/@aws-sdk/middleware-logger": { "version": "3.523.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.523.0.tgz", "integrity": "sha512-PeDNJNhfiaZx54LBaLTXzUaJ9LXFwDFFIksipjqjvxMafnoVcQwKbkoPUWLe5ytT4nnL1LogD3s55mERFUsnwg==", @@ -561,7 +580,7 @@ "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/middleware-recursion-detection": { + "node_modules/@aws-sdk/middleware-recursion-detection": { "version": "3.523.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.523.0.tgz", "integrity": "sha512-nZ3Vt7ehfSDYnrcg/aAfjjvpdE+61B3Zk68i6/hSUIegT3IH9H1vSW67NDKVp+50hcEfzWwM2HMPXxlzuyFyrw==", @@ -575,7 +594,23 @@ "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/middleware-user-agent": { + "node_modules/@aws-sdk/middleware-sdk-sqs": { + "version": "3.525.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sqs/-/middleware-sdk-sqs-3.525.0.tgz", + "integrity": "sha512-w+H1VOajANjo5gxe2/rQjO7HEuIiEyuFNZzNsztH1E9JBZ01Z2EvEYAfZTkCOV40Or4I2lTHnyt9voXIxW+bzw==", + "dependencies": { + "@aws-sdk/types": "3.523.0", + "@smithy/smithy-client": "^2.4.2", + "@smithy/types": "^2.10.1", + "@smithy/util-hex-encoding": "^2.1.1", + "@smithy/util-utf8": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent": { "version": "3.525.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.525.0.tgz", "integrity": "sha512-4al/6uO+t/QIYXK2OgqzDKQzzLAYJza1vWFS+S0lJ3jLNGyLB5BMU5KqWjDzevYZ4eCnz2Nn7z0FveUTNz8YdQ==", @@ -590,7 +625,7 @@ "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/region-config-resolver": { + "node_modules/@aws-sdk/region-config-resolver": { "version": "3.525.0", "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.525.0.tgz", "integrity": "sha512-8kFqXk6UyKgTMi7N7QlhA6qM4pGPWbiUXqEY2RgUWngtxqNFGeM9JTexZeuavQI+qLLe09VPShPNX71fEDcM6w==", @@ -606,7 +641,7 @@ "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/token-providers": { + "node_modules/@aws-sdk/token-providers": { "version": "3.525.0", "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.525.0.tgz", "integrity": "sha512-puVjbxuK0Dq7PTQ2HdddHy2eQjOH8GZbump74yWJa6JVpRW84LlOcNmP+79x4Kscvz2ldWB8XDFw/pcCiSDe5A==", @@ -622,7 +657,7 @@ "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/types": { + "node_modules/@aws-sdk/types": { "version": "3.523.0", "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.523.0.tgz", "integrity": "sha512-AqGIu4u+SxPiUuNBp2acCVcq80KDUFjxe6e3cMTvKWTzCbrVk1AXv0dAaJnCmdkWIha6zJDWxpIk/aL4EGhZ9A==", @@ -634,7 +669,7 @@ "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/util-endpoints": { + "node_modules/@aws-sdk/util-endpoints": { "version": "3.525.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.525.0.tgz", "integrity": "sha512-DIW7WWU5tIGkeeKX6NJUyrEIdWMiqjLQG3XBzaUj+ufIENwNjdAHhlD8l2vX7Yr3JZRT6yN/84wBCj7Tw1xd1g==", @@ -648,7 +683,18 @@ "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/util-user-agent-browser": { + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.495.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.495.0.tgz", + "integrity": "sha512-MfaPXT0kLX2tQaR90saBT9fWQq2DHqSSJRzW+MZWsmF+y5LGCOhO22ac/2o6TKSQm7h0HRc2GaADqYYYor62yg==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-browser": { "version": "3.523.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.523.0.tgz", "integrity": "sha512-6ZRNdGHX6+HQFqTbIA5+i8RWzxFyxsZv8D3soRfpdyWIKkzhSz8IyRKXRciwKBJDaC7OX2jzGE90wxRQft27nA==", @@ -659,7 +705,7 @@ "tslib": "^2.5.0" } }, - "node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/util-user-agent-node": { + "node_modules/@aws-sdk/util-user-agent-node": { "version": "3.525.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.525.0.tgz", "integrity": "sha512-88Wjt4efyUSBGcyIuh1dvoMqY1k15jpJc5A/3yi67clBQEFsu9QCodQCQPqmRjV3VRcMtBOk+jeCTiUzTY5dRQ==", @@ -681,88 +727,6 @@ } } }, - "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.525.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.525.0.tgz", - "integrity": "sha512-RNWQGuSBQZhl3iqklOslUEfQ4br1V3DCPboMpeqFtddUWJV3m2u2extFur9/4Uy+1EHVF120IwZUKtd8dF+ibw==", - "dependencies": { - "@aws-sdk/types": "3.523.0", - "@smithy/fetch-http-handler": "^2.4.3", - "@smithy/node-http-handler": "^2.4.1", - "@smithy/property-provider": "^2.1.3", - "@smithy/protocol-http": "^3.2.1", - "@smithy/smithy-client": "^2.4.2", - "@smithy/types": "^2.10.1", - "@smithy/util-stream": "^2.1.3", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http/node_modules/@aws-sdk/types": { - "version": "3.523.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.523.0.tgz", - "integrity": "sha512-AqGIu4u+SxPiUuNBp2acCVcq80KDUFjxe6e3cMTvKWTzCbrVk1AXv0dAaJnCmdkWIha6zJDWxpIk/aL4EGhZ9A==", - "dependencies": { - "@smithy/types": "^2.10.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/middleware-sdk-sqs": { - "version": "3.525.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sqs/-/middleware-sdk-sqs-3.525.0.tgz", - "integrity": "sha512-w+H1VOajANjo5gxe2/rQjO7HEuIiEyuFNZzNsztH1E9JBZ01Z2EvEYAfZTkCOV40Or4I2lTHnyt9voXIxW+bzw==", - "dependencies": { - "@aws-sdk/types": "3.523.0", - "@smithy/smithy-client": "^2.4.2", - "@smithy/types": "^2.10.1", - "@smithy/util-hex-encoding": "^2.1.1", - "@smithy/util-utf8": "^2.1.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/middleware-sdk-sqs/node_modules/@aws-sdk/types": { - "version": "3.523.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.523.0.tgz", - "integrity": "sha512-AqGIu4u+SxPiUuNBp2acCVcq80KDUFjxe6e3cMTvKWTzCbrVk1AXv0dAaJnCmdkWIha6zJDWxpIk/aL4EGhZ9A==", - "dependencies": { - "@smithy/types": "^2.10.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/types": { - "version": "3.489.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.489.0.tgz", - "integrity": "sha512-kcDtLfKog/p0tC4gAeqJqWxAiEzfe2LRPnKamvSG2Mjbthx4R/alE2dxyIq/wW+nvRv0fqR3OD5kD1+eVfdr/w==", - "dependencies": { - "@smithy/types": "^2.8.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/util-locate-window": { - "version": "3.465.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.465.0.tgz", - "integrity": "sha512-f+QNcWGswredzC1ExNAB/QzODlxwaTdXkNT5cvke2RLX8SFU5pYk6h4uCtWC0vWPELzOfMfloBrJefBzlarhsw==", - "dependencies": { - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/@aws-sdk/util-utf8-browser": { "version": "3.259.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", @@ -1464,9 +1428,8 @@ }, "node_modules/@babel/traverse/node_modules/globals": { "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -3188,9 +3151,9 @@ "license": "MIT" }, "node_modules/@types/semver": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.7.tgz", - "integrity": "sha512-/wdoPq1QqkSj9/QOeKkFquEuPzQbHTWAMPH/PaUMB+JuR31lXhlWXRZ52IpfDYVlDOUBvX09uBrPwxGT1hjNBg==", + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", "dev": true }, "node_modules/@types/send": { @@ -3279,16 +3242,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.0.1.tgz", - "integrity": "sha512-OLvgeBv3vXlnnJGIAgCLYKjgMEU+wBGj07MQ/nxAaON+3mLzX7mJbhRYrVGiVvFiXtwFlkcBa/TtmglHy0UbzQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.1.0.tgz", + "integrity": "sha512-j6vT/kCulhG5wBmGtstKeiVr1rdXE4nk+DT1k6trYkwlrvW9eOF5ZbgKnd/YR6PcM4uTEXa0h6Fcvf6X7Dxl0w==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "7.0.1", - "@typescript-eslint/type-utils": "7.0.1", - "@typescript-eslint/utils": "7.0.1", - "@typescript-eslint/visitor-keys": "7.0.1", + "@typescript-eslint/scope-manager": "7.1.0", + "@typescript-eslint/type-utils": "7.1.0", + "@typescript-eslint/utils": "7.1.0", + "@typescript-eslint/visitor-keys": "7.1.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -3314,15 +3277,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.0.1.tgz", - "integrity": "sha512-8GcRRZNzaHxKzBPU3tKtFNing571/GwPBeCvmAUw0yBtfE2XVd0zFKJIMSWkHJcPQi0ekxjIts6L/rrZq5cxGQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.1.0.tgz", + "integrity": "sha512-V1EknKUubZ1gWFjiOZhDSNToOjs63/9O0puCgGS8aDOgpZY326fzFu15QAUjwaXzRZjf/qdsdBrckYdv9YxB8w==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.0.1", - "@typescript-eslint/types": "7.0.1", - "@typescript-eslint/typescript-estree": "7.0.1", - "@typescript-eslint/visitor-keys": "7.0.1", + "@typescript-eslint/scope-manager": "7.1.0", + "@typescript-eslint/types": "7.1.0", + "@typescript-eslint/typescript-estree": "7.1.0", + "@typescript-eslint/visitor-keys": "7.1.0", "debug": "^4.3.4" }, "engines": { @@ -3342,13 +3305,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.0.1.tgz", - "integrity": "sha512-v7/T7As10g3bcWOOPAcbnMDuvctHzCFYCG/8R4bK4iYzdFqsZTbXGln0cZNVcwQcwewsYU2BJLay8j0/4zOk4w==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.1.0.tgz", + "integrity": "sha512-6TmN4OJiohHfoOdGZ3huuLhpiUgOGTpgXNUPJgeZOZR3DnIpdSgtt83RS35OYNNXxM4TScVlpVKC9jyQSETR1A==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.0.1", - "@typescript-eslint/visitor-keys": "7.0.1" + "@typescript-eslint/types": "7.1.0", + "@typescript-eslint/visitor-keys": "7.1.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -3359,13 +3322,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.0.1.tgz", - "integrity": "sha512-YtT9UcstTG5Yqy4xtLiClm1ZpM/pWVGFnkAa90UfdkkZsR1eP2mR/1jbHeYp8Ay1l1JHPyGvoUYR6o3On5Nhmw==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.1.0.tgz", + "integrity": "sha512-UZIhv8G+5b5skkcuhgvxYWHjk7FW7/JP5lPASMEUoliAPwIH/rxoUSQPia2cuOj9AmDZmwUl1usKm85t5VUMew==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.0.1", - "@typescript-eslint/utils": "7.0.1", + "@typescript-eslint/typescript-estree": "7.1.0", + "@typescript-eslint/utils": "7.1.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -3386,9 +3349,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.0.1.tgz", - "integrity": "sha512-uJDfmirz4FHib6ENju/7cz9SdMSkeVvJDK3VcMFvf/hAShg8C74FW+06MaQPODHfDJp/z/zHfgawIJRjlu0RLg==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.1.0.tgz", + "integrity": "sha512-qTWjWieJ1tRJkxgZYXx6WUYtWlBc48YRxgY2JN1aGeVpkhmnopq+SUC8UEVGNXIvWH7XyuTjwALfG6bFEgCkQA==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -3399,13 +3362,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.0.1.tgz", - "integrity": "sha512-SO9wHb6ph0/FN5OJxH4MiPscGah5wjOd0RRpaLvuBv9g8565Fgu0uMySFEPqwPHiQU90yzJ2FjRYKGrAhS1xig==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.1.0.tgz", + "integrity": "sha512-k7MyrbD6E463CBbSpcOnwa8oXRdHzH1WiVzOipK3L5KSML92ZKgUBrTlehdi7PEIMT8k0bQixHUGXggPAlKnOQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.0.1", - "@typescript-eslint/visitor-keys": "7.0.1", + "@typescript-eslint/types": "7.1.0", + "@typescript-eslint/visitor-keys": "7.1.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -3451,17 +3414,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.0.1.tgz", - "integrity": "sha512-oe4his30JgPbnv+9Vef1h48jm0S6ft4mNwi9wj7bX10joGn07QRfqIqFHoMiajrtoU88cIhXf8ahwgrcbNLgPA==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.1.0.tgz", + "integrity": "sha512-WUFba6PZC5OCGEmbweGpnNJytJiLG7ZvDBJJoUcX4qZYf1mGZ97mO2Mps6O2efxJcJdRNpqweCistDbZMwIVHw==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "7.0.1", - "@typescript-eslint/types": "7.0.1", - "@typescript-eslint/typescript-estree": "7.0.1", + "@typescript-eslint/scope-manager": "7.1.0", + "@typescript-eslint/types": "7.1.0", + "@typescript-eslint/typescript-estree": "7.1.0", "semver": "^7.5.4" }, "engines": { @@ -3476,12 +3439,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.0.1.tgz", - "integrity": "sha512-hwAgrOyk++RTXrP4KzCg7zB2U0xt7RUU0ZdMSCsqF3eKUwkdXUMyTb0qdCuji7VIbcpG62kKTU9M1J1c9UpFBw==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.1.0.tgz", + "integrity": "sha512-FhUqNWluiGNzlvnDZiXad4mZRhtghdoKW6e98GoEOYSu5cND+E39rG5KwJMUzeENwm1ztYBRqof8wMLP+wNPIA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.0.1", + "@typescript-eslint/types": "7.1.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -3735,9 +3698,9 @@ } }, "node_modules/applicationinsights/node_modules/@opentelemetry/api": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.8.0.tgz", - "integrity": "sha512-I/s6F7yKUDdtMsoBWXJe8Qz40Tui5vsuKCWJEWVL+5q9sSWRzzx6v2KeNsOBEwd94j0eWkpWCH4yB6rZg9Mf0w==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.7.0.tgz", + "integrity": "sha512-AdY5wvN0P2vXBi3b29hxZgSFvdhdxPB9+f0B6s//P9Q8nibRWeA3cHm8UmLpio9ABigkVHJ5NMPk+Mz8VCCyrw==", "engines": { "node": ">=8.0.0" } @@ -8453,9 +8416,8 @@ }, "node_modules/lint-staged/node_modules/chalk": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", - "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "dev": true, + "license": "MIT", "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" }, @@ -8613,9 +8575,9 @@ } }, "node_modules/lint-staged/node_modules/npm-run-path": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", - "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", "dev": true, "dependencies": { "path-key": "^4.0.0" @@ -9487,18 +9449,16 @@ }, "node_modules/nodemon/node_modules/has-flag": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/nodemon/node_modules/supports-color": { "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^3.0.0" }, @@ -10290,9 +10250,6 @@ "version": "4.6.13", "resolved": "https://registry.npmjs.org/redis/-/redis-4.6.13.tgz", "integrity": "sha512-MHgkS4B+sPjCXpf+HfdetBwbRz6vCtsceTmw1pHNYJAsYxrfpOP6dz+piJWGos8wqG7qb3vj/Rrc5qOlmInUuA==", - "workspaces": [ - "./packages/*" - ], "dependencies": { "@redis/bloom": "1.2.0", "@redis/client": "1.5.14", diff --git a/package.json b/package.json index 5baf0ce0..553e627c 100644 --- a/package.json +++ b/package.json @@ -150,8 +150,8 @@ "@types/superagent": "^8.1.4", "@types/supertest": "^6.0.2", "@types/uuid": "^9.0.8", - "@typescript-eslint/eslint-plugin": "^7.0.1", - "@typescript-eslint/parser": "^7.0.1", + "@typescript-eslint/eslint-plugin": "^7.1.0", + "@typescript-eslint/parser": "^7.1.0", "audit-ci": "^6.6.1", "concurrently": "^8.2.2", "cookie-session": "^2.1.0",