fix(frontend): keep entity and message deletes in sync
This commit is contained in:
@@ -21,7 +21,7 @@ class EntityService(
|
||||
|
||||
/** Returns all virtual entities. */
|
||||
fun findAll(): List<VirtualEntityResponseDto> =
|
||||
virtualEntityRepository.findAll().map { VirtualEntityResponseDto.from(it) }
|
||||
virtualEntityRepository.findAllByActiveTrue().map { VirtualEntityResponseDto.from(it) }
|
||||
|
||||
/** Returns one entity by ID, or null if not found. */
|
||||
fun findById(id: UUID): VirtualEntityResponseDto? =
|
||||
|
||||
@@ -138,4 +138,32 @@ class TaskGeneratedMessageControllerTest {
|
||||
.andExpect(jsonPath("$").isArray)
|
||||
.andExpect(jsonPath("$.length()").value(0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun should_deleteOnlySelectedHistoryItem_when_multipleMessagesExist() {
|
||||
val task = createTask()
|
||||
val firstMessage = generatedMessageHistoryRepository.save(
|
||||
GeneratedMessageHistory(
|
||||
task = task,
|
||||
label = "Message #1",
|
||||
content = "SUBJECT: First\nBODY:\nHello"
|
||||
)
|
||||
)
|
||||
val secondMessage = generatedMessageHistoryRepository.save(
|
||||
GeneratedMessageHistory(
|
||||
task = task,
|
||||
label = "Message #2",
|
||||
content = "SUBJECT: Second\nBODY:\nHi"
|
||||
)
|
||||
)
|
||||
|
||||
mockMvc.perform(delete("/api/v1/tasks/${task.id}/generated-messages/${firstMessage.id}").cookie(authCookie()))
|
||||
.andExpect(status().isNoContent)
|
||||
|
||||
mockMvc.perform(get("/api/v1/tasks/${task.id}/generated-messages").cookie(authCookie()))
|
||||
.andExpect(status().isOk)
|
||||
.andExpect(jsonPath("$.length()").value(1))
|
||||
.andExpect(jsonPath("$[0].id").value(secondMessage.id.toString()))
|
||||
.andExpect(jsonPath("$[0].label").value("Message #2"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,17 @@ class VirtualEntityControllerTest {
|
||||
.andExpect(status().isOk).andExpect(jsonPath("$").isArray).andExpect(jsonPath("$[0].name").value("Test Entity"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun should_returnOnlyActiveEntities_when_getAllEntities() {
|
||||
virtualEntityRepository.save(VirtualEntity(name = "Active Entity", email = "active@condado.com", jobTitle = "Tester", active = true))
|
||||
virtualEntityRepository.save(VirtualEntity(name = "Inactive Entity", email = "inactive@condado.com", jobTitle = "Tester", active = false))
|
||||
|
||||
mockMvc.perform(get("/api/v1/virtual-entities").cookie(authCookie()))
|
||||
.andExpect(status().isOk)
|
||||
.andExpect(jsonPath("$.length()").value(1))
|
||||
.andExpect(jsonPath("$[0].name").value("Active Entity"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun should_return200AndEntity_when_getById() {
|
||||
val entity = virtualEntityRepository.save(VirtualEntity(name = "Test Entity", email = "entity@condado.com", jobTitle = "Test Job"))
|
||||
|
||||
@@ -294,6 +294,45 @@ describe('EditTaskPage', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('should_removeOnlyDeletedGeneratedMessage_when_deleteSucceedsWithoutRefetch', async () => {
|
||||
persistedHistory = [
|
||||
{
|
||||
id: 'message-2',
|
||||
taskId: 'task-1',
|
||||
label: 'Message #2',
|
||||
content: 'SUBJECT: Second\nBODY:\nSecond output',
|
||||
createdAt: '2026-03-27T12:10:00Z',
|
||||
},
|
||||
{
|
||||
id: 'message-1',
|
||||
taskId: 'task-1',
|
||||
label: 'Message #1',
|
||||
content: 'SUBJECT: First\nBODY:\nFirst output',
|
||||
createdAt: '2026-03-27T12:00:00Z',
|
||||
},
|
||||
]
|
||||
vi.mocked(tasksApi.getTaskGeneratedMessages).mockResolvedValue(persistedHistory)
|
||||
vi.mocked(tasksApi.deleteTaskGeneratedMessage).mockResolvedValue(undefined)
|
||||
|
||||
renderPage()
|
||||
|
||||
const secondMessageHistoryItem = await screen.findByRole('button', { name: /^message #2$/i })
|
||||
expect(await screen.findByRole('button', { name: /^message #1$/i })).toBeInTheDocument()
|
||||
|
||||
fireEvent.click(
|
||||
screen.getByRole('button', {
|
||||
name: /delete message #1/i,
|
||||
})
|
||||
)
|
||||
|
||||
await waitFor(() => {
|
||||
expect(tasksApi.deleteTaskGeneratedMessage).toHaveBeenCalledWith('task-1', 'message-1')
|
||||
expect(screen.queryByRole('button', { name: /^message #1$/i })).not.toBeInTheDocument()
|
||||
expect(secondMessageHistoryItem).toBeInTheDocument()
|
||||
expect(screen.getByText(/Second output/i)).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
it('should_loadPersistedGeneratedMessageHistory_when_pageLoads', async () => {
|
||||
persistedHistory = [
|
||||
{
|
||||
|
||||
@@ -89,6 +89,23 @@ describe('EntitiesPage', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('should_removeDeletedEntityFromList_when_deleteSucceeds', async () => {
|
||||
vi.mocked(entitiesApi.getEntities).mockResolvedValue([mockEntity])
|
||||
vi.mocked(entitiesApi.deleteEntity).mockResolvedValue(undefined)
|
||||
|
||||
render(<EntitiesPage />, { wrapper })
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Test Entity')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: /delete|deactivate/i }))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText('Test Entity')).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
it('should_renderDetailLink_when_entitiesLoaded', async () => {
|
||||
vi.mocked(entitiesApi.getEntities).mockResolvedValue([mockEntity])
|
||||
render(<EntitiesPage />, { wrapper })
|
||||
|
||||
@@ -255,8 +255,15 @@ export default function EditTaskPage() {
|
||||
|
||||
const deleteGeneratedMessageMutation = useMutation({
|
||||
mutationFn: (messageId: string) => deleteTaskGeneratedMessage(taskId, messageId),
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries({ queryKey: ['task-generated-messages', taskId] })
|
||||
onSuccess: ( _data, messageId) => {
|
||||
queryClient.setQueryData(
|
||||
['task-generated-messages', taskId],
|
||||
(
|
||||
currentMessages:
|
||||
| Awaited<ReturnType<typeof getTaskGeneratedMessages>>
|
||||
| undefined
|
||||
) => currentMessages?.filter((message) => message.id !== messageId) ?? []
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -37,7 +37,13 @@ export default function EntitiesPage() {
|
||||
|
||||
const deleteMutation = useMutation({
|
||||
mutationFn: (id: string) => deleteEntity(id),
|
||||
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['entities'] }),
|
||||
onSuccess: (_data, id) => {
|
||||
queryClient.setQueryData(
|
||||
['entities'],
|
||||
(currentEntities: Awaited<ReturnType<typeof getEntities>> | undefined) =>
|
||||
currentEntities?.filter((entity) => entity.id !== id) ?? []
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user