feat: Swap mapping direction#107
Conversation
jhfgloria
left a comment
There was a problem hiding this comment.
Left some comments. The PR is quite big (and visual), so probably I would need to test it locally to make more sense of it.
| await Promise.all( | ||
| Object.entries(EndpointConfig).map(async ([account, _]) => { | ||
| services = await Promise.all( | ||
| ids.map(async id => await getServiceById(id, account)), |
There was a problem hiding this comment.
I think we should probably use this API instead, because we can do it in one request? https://github.com/PagerDuty/service-search-service/blob/master/apps/api/doc/api/service_directory.md#api-service_directory-list_services
| mapping => mapping.serviceId === service.id, | ||
| e => | ||
| e.integrationKey === | ||
| ent?.metadata.annotations?.['pagerduty.com/integration-key'], |
There was a problem hiding this comment.
Are there any guarantees that at this point the integration-key was set? 🤔 Why not searching by integration-key OR service-id.
| result.mappings.push({ | ||
| entityRef: '', | ||
| entityName: '', | ||
| integrationKey: entityMapping?.integrationKey, | ||
| serviceId: entityMapping?.serviceId ?? '', | ||
| status: 'NotMapped', | ||
| serviceName: '', | ||
| team: '', | ||
| escalationPolicy: '', | ||
| serviceUrl: '', | ||
| account: '', | ||
| }); |
There was a problem hiding this comment.
Do we need to push this empty state?
| }); | ||
|
|
||
| // GET /mapping/entity | ||
| router.get('/mapping/entity', async (_, response) => { |
There was a problem hiding this comment.
Please don't remove any methods. Instead mark them as deprecated. There is a chance that people only update the frontend or just the backend and then there will be missing methods.
| search: debouncedSearchQuery, | ||
| searchFields: ['metadata.name', 'spec.owner'], | ||
| }), | ||
| staleTime: 5 * 60 * 1000, |
There was a problem hiding this comment.
Why 5 minutes? 🤔 Is it worth caching at all?
There was a problem hiding this comment.
hmm, not sure why did I include this back then, just removed it!
| const [pageSize, setPageSize] = useState(10); | ||
| const [searchQuery, setSearchQuery] = useState(''); | ||
| const [debouncedSearchQuery, setDebouncedSearchQuery] = useState(''); | ||
| useDebounce(() => setDebouncedSearchQuery(searchQuery), 500, [searchQuery]); |
There was a problem hiding this comment.
Use debounce used like this is so awkward... Shouldn't it return something? What's the point of the hook at all? 🤔
plugins/backstage-plugin/src/components/PagerDutyPage/MappingsTable/StatusCell.tsx
Show resolved
Hide resolved
| } | ||
| } | ||
|
|
||
| export async function getServicesByIdsServiceDirectory( |
There was a problem hiding this comment.
I don't think we need to expose the calling service from PagerDuty. getServicesByIdsAndAccount would be more readable and not expose the fact that the call is made to ServicesDirectory.
| }; | ||
|
|
||
| const formattedEntity = { | ||
| name: entity?.metadata?.name, |
There was a problem hiding this comment.
Why would the entity be null? Doesn't it come from the catalog API? Also, if it is null would be better practice to early return here, instead of dragging the ? around forever?
| const foundServices = pagerDutyServices.filter( | ||
| s => s.id === serviceId, | ||
| ); | ||
| if (foundServices.length > 0) { | ||
| service = foundServices[0]; | ||
| } |
There was a problem hiding this comment.
| const foundServices = pagerDutyServices.filter( | |
| s => s.id === serviceId, | |
| ); | |
| if (foundServices.length > 0) { | |
| service = foundServices[0]; | |
| } | |
| service = pagerDutyServices.find(s => s.id === serviceId); |
| account, | ||
| ); | ||
| } catch (e) { | ||
| // Service might not exist, just continue |
There was a problem hiding this comment.
I think this type of error is only valid if the error is a 404. Otherwise you will not know if there is a map or not and could decide to map something else.
jhfgloria
left a comment
There was a problem hiding this comment.
LGTM! Let's just make some tests in the ServiceMappingComponent (I think it is the topmost component) and test the router.ts new endpoint (which I also think is the topmost backend piece of software). There is no tests in the PR and I think there should be.
c38fcb1 to
ed2ba57
Compare
ed2ba57 to
582e3ba
Compare
| describe('createRouter', () => { | ||
| let app: express.Express; | ||
| let store: PagerDutyBackendStore; | ||
| const mockCatalogApi = { |
There was a problem hiding this comment.
Do we need to mock the entire class? 🤔
There was a problem hiding this comment.
I mocked it for TS reasons only
| expect(response.status).toEqual(200); | ||
| expect(response.body).toHaveProperty('entities'); | ||
| expect(response.body).toHaveProperty('totalCount'); | ||
| expect(Array.isArray(response.body.entities)).toBe(true); |
There was a problem hiding this comment.
Well, [ ] is also an array, that doesn't make this test more accurate. I think we should check if the responde contains the expected mapping, and not just check if it is an array. Otherwise I can change the implementation of the controller to just return an empty array and it will pass anyway.
|
|
||
| expect(response.status).toEqual(200); | ||
| expect(response.body).toHaveProperty('entities'); | ||
| expect(response.body).toHaveProperty('totalCount'); |
There was a problem hiding this comment.
Again, we're not asserting the return of the request, and we should.
| expect(response.status).toEqual(200); | ||
| expect(response.body).toHaveProperty('entities'); | ||
| expect(response.body).toHaveProperty('totalCount'); | ||
| }); |
There was a problem hiding this comment.
Ergh... these tests look all the same thing. The fact that we mock everything in the mockCatalogApi doesn't allow for testing much. The fact that you never assert the contents of entities is the prove itself that the test doesn't really matter. Tbh, unless we change these tests to actually alter the catalog that is queried, I'd even prefer to just wipe these tests. They're not testing anything in my opinion.
|
|
||
| expect(response.status).toEqual(200); | ||
| expect(response.body).toHaveProperty('entities'); | ||
| expect(response.body).toHaveProperty('totalCount'); |
There was a problem hiding this comment.
Again, not testing anything.
| await act(async () => { | ||
| fireEvent.change(searchInput, { target: { value: 'my-component' } }); | ||
| }); | ||
|
|
||
| await act(async () => { | ||
| jest.advanceTimersByTime(500); | ||
| }); |
There was a problem hiding this comment.
I don't think modern RTL tests still require act wrapping. fireEvent is already wrapped in a act. For advanceTimersByTime you may be need, because it is not a RTL event.
| expect(screen.getByText('Out of Sync')).toBeInTheDocument(); | ||
| expect(screen.getByText('Not Mapped')).toBeInTheDocument(); | ||
| expect( | ||
| screen.getByText('Error occured while fetching service'), |
There was a problem hiding this comment.
Does this fit the table column? 🤔
There was a problem hiding this comment.
it does not but gets dotted out, on hover the full text is displayed
* feat: Swap service mapping direction * feat: Get rid of the old MappingTable * feat: Use a different API for retrieving PD services * fix: Revert entity mappings * fix: Resolve conflicts * fix: Service mapping creation and update * feat: Add unit tests * fix: Remove unused import * fix: Add proper expects for router unit tests * fix: Get rid of redundant unit test expects * fix: Mock catalog api the backstage way
Description
To improve loading performance of the mappings page we swap the direction of the data loaded. Until now were were mapping Backstage entities to PagerDuty services, now we swap this and will do the opposite. In this PR I've updated the mappings table to the new Backstage UI table and updated the way we load the data for the component.
Affected plugin
Type of change
Checklist
If this is a breaking change 👇
Acknowledgement
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.
Disclaimer: We value your time and bandwidth. As such, any pull requests created on non-triaged issues might not be successful.