Skip to content

Commit

Permalink
feat: add/remove keys from task
Browse files Browse the repository at this point in the history
  • Loading branch information
stepan662 committed Jul 22, 2024
1 parent b7b60fe commit 5a165f4
Show file tree
Hide file tree
Showing 10 changed files with 185 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ class TaskController(
@RequestBody @Valid
dto: CreateTaskRequest,
): TaskModel {
val task = taskService.createTask(projectHolder.projectEntity, dto)
val id = taskService.createTask(projectHolder.projectEntity, dto).id
val task = taskService.getTask(projectHolder.projectEntity, id)

return taskModelAssembler.toModel(task)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
package io.tolgee.api.v2.controllers.task

import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import io.tolgee.ProjectAuthControllerTest
import io.tolgee.constants.Message
import io.tolgee.development.testDataBuilder.data.TaskTestData
import io.tolgee.dtos.request.task.CalculateScopeRequest
import io.tolgee.dtos.request.task.CreateTaskRequest
import io.tolgee.dtos.request.task.UpdateTaskRequest
import io.tolgee.dtos.request.task.*
import io.tolgee.fixtures.andAssertThatJson
import io.tolgee.fixtures.andIsBadRequest
import io.tolgee.fixtures.andIsOk
import io.tolgee.fixtures.node
import io.tolgee.model.enums.TaskType
import io.tolgee.testing.annotations.ProjectJWTAuthTestMethod
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import java.math.BigDecimal
Expand Down Expand Up @@ -63,7 +59,7 @@ class TaskControllerTest : ProjectAuthControllerTest("/v2/projects/") {
node("name").isEqualTo("Another task")
node("assignees[0].name").isEqualTo(testData.orgMember.self.name)
node("language.tag").isEqualTo(testData.englishLanguage.tag)
node("keys").isEqualTo(keys.toSortedSet())
node("totalItems").isEqualTo(keys.size)
}

performProjectAuthGet("tasks").andAssertThatJson {
Expand Down Expand Up @@ -144,24 +140,21 @@ class TaskControllerTest : ProjectAuthControllerTest("/v2/projects/") {
@Test
@ProjectJWTAuthTestMethod
fun `can add keys`() {
val response =
performProjectAuthPut(
"tasks/${testData.createdTask.self.id}",
UpdateTaskRequest(
addKeys = testData.keysOutOfTask.map { it.self.id }.toMutableSet(),
),
).andIsOk.andReturn().response.contentAsString
// Parse JSON response
val jsonResponse = jacksonObjectMapper().readTree(response)

// Extract keys array from JSON response and convert to Set of strings
val actualKeys = jsonResponse["keys"].elements().asSequence().map { it.asLong() }.toSet()

// Calculate expected keys set
val expectedKeys = (testData.keysInTask union testData.keysOutOfTask).map { it.self.id }.toSet()

// Assert that actual keys match expected keys
assertEquals(expectedKeys, actualKeys, "The keys in the response should match the expected keys")
performProjectAuthPut(
"tasks/${testData.createdTask.self.id}/keys",
UpdateTaskKeysRequest(
addKeys = testData.keysOutOfTask.map { it.self.id }.toMutableSet(),
),
).andIsOk

performProjectAuthGet(
"tasks/${testData.createdTask.self.id}",
).andIsOk.andAssertThatJson {
// Calculate expected keys set
val expectedItems = (testData.keysInTask union testData.keysOutOfTask).size

node("totalItems").isEqualTo(expectedItems)
}
}

@Test
Expand All @@ -170,16 +163,18 @@ class TaskControllerTest : ProjectAuthControllerTest("/v2/projects/") {
val allKeys = testData.keysInTask.map { it.self.id }.toMutableSet()
val keysToRemove = mutableSetOf(allKeys.first())
val remainingKeys = allKeys.subtract(keysToRemove)
val response =
performProjectAuthPut(
"tasks/${testData.createdTask.self.id}",
UpdateTaskRequest(
removeKeys = keysToRemove,
),
).andIsOk.andReturn().response.contentAsString
val jsonResponse = jacksonObjectMapper().readTree(response)
val actualKeys = jsonResponse["keys"].elements().asSequence().map { it.asLong() }.toSet()
assertEquals(remainingKeys, actualKeys, "The keys in the response should match the expected keys")
performProjectAuthPut(
"tasks/${testData.createdTask.self.id}/keys",
UpdateTaskKeysRequest(
removeKeys = keysToRemove,
),
).andIsOk

performProjectAuthGet(
"tasks/${testData.createdTask.self.id}",
).andIsOk.andAssertThatJson {
node("totalItems").isEqualTo(remainingKeys.size)
}
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class CursorUtilUnitTest {
mtProvider = null,
commentCount = 0,
unresolvedCommentCount = 1,
assignedTaskId = 1
),
),
contextPresent = false,
Expand Down
13 changes: 7 additions & 6 deletions backend/data/src/main/kotlin/io/tolgee/service/TaskService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class TaskService(
}
}

@Transactional
fun createTask(
project: Project,
dto: CreateTaskRequest,
Expand All @@ -81,7 +82,6 @@ class TaskService(
lastErr = e
}
}

throw lastErr
}

Expand Down Expand Up @@ -208,12 +208,13 @@ class TaskService(
}

dto.addKeys?.let { toAdd ->
val translationsToAdd = getOnlyProjectKeys(projectEntity, task.language.id, task.type, toAdd)
val translationsToAdd = getOrCreateTranslations(task.language.id, toAdd)
val translationIdsToAdd = translationsToAdd.map { it.id }.toMutableSet()
val existingTranslations = task.translations.map { it.translation.id }.toMutableSet()
val nonExistingTranslations = translationsToAdd.subtract(existingTranslations).toMutableSet()
val taskTranslationsToAdd =
nonExistingTranslations
.map { TaskTranslation(task, entityManager.getReference(Translation::class.java, it)) }
val nonExistingTranslationIds = translationIdsToAdd.subtract(existingTranslations).toMutableSet()
val taskTranslationsToAdd = translationsToAdd
.filter { nonExistingTranslationIds.contains(it.id) }
.map { TaskTranslation(task, it) }
task.translations = task.translations.union(taskTranslationsToAdd).toMutableSet()
taskTranslationRepository.saveAll(taskTranslationsToAdd)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ import { BatchActions, BatchJobModel } from './types';
import { OperationPreTranslate } from './OperationPreTranslate';
import { SelectAllCheckbox } from './SelectAllCheckbox';
import { OperationExportTranslations } from './OperationExportTranslations';
import { OperationCreateTask } from './OperationCreateTask';
import { OperationTaskCreate } from './OperationTaskCreate';
import { OperationTaskAddKeys } from './OperationTaskAddKeys';
import { OperationTaskRemoveKeys } from './OperationTaskRemoveKeys';

const StyledContainer = styled('div')`
position: absolute;
Expand Down Expand Up @@ -119,8 +121,12 @@ export const BatchOperations = ({ open, onClose }: Props) => {
return <OperationMarkAsTranslated {...sharedProps} />;
case 'mark_as_reviewed':
return <OperationMarkAsReviewed {...sharedProps} />;
case 'create_task':
return <OperationCreateTask {...sharedProps} />;
case 'task_create':
return <OperationTaskCreate {...sharedProps} />;
case 'task_add_keys':
return <OperationTaskAddKeys {...sharedProps} />;
case 'task_remove_keys':
return <OperationTaskRemoveKeys {...sharedProps} />;
case 'add_tags':
return <OperationAddTags {...sharedProps} />;
case 'remove_tags':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,21 @@ export const BatchSelect = ({ value, onChange }: Props) => {
enabled: canViewTranslations,
},
{
id: 'create_task',
id: 'task_create',
label: t('batch_operations_create_task'),
divider: true,
enabled: canEditKey,
},
{
id: 'task_add_keys',
label: t('batch_operations_task_add_keys'),
enabled: canEditKey,
},
{
id: 'task_remove_keys',
label: t('batch_operations_task_remove_keys'),
enabled: canEditKey,
},
{
id: 'add_tags',
label: t('batch_operations_add_tags'),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { useState } from 'react';
import { useTranslate } from '@tolgee/react';

import { useApiMutation } from 'tg.service/http/useQueryApi';
import { useProject } from 'tg.hooks/useProject';
import { TextField } from 'tg.component/common/TextField';

import { useTranslationsSelector } from '../context/TranslationsContext';
import { OperationContainer } from './components/OperationContainer';
import { BatchOperationsSubmit } from './components/BatchOperationsSubmit';
import { OperationProps } from './types';
import { messageService } from 'tg.service/MessageService';
import { usePrefilter } from '../prefilters/usePrefilter';

type Props = OperationProps;

export const OperationTaskAddKeys = ({ disabled, onFinished }: Props) => {
const prefilter = usePrefilter();
const [task, setTask] = useState(prefilter.task ? prefilter.task : undefined);
const project = useProject();
const { t } = useTranslate();

const selection = useTranslationsSelector((c) => c.selection);

const addTaskKeysLoadable = useApiMutation({
url: '/v2/projects/{projectId}/tasks/{taskId}/keys',
method: 'put',
});

function handleAddKeys() {
addTaskKeysLoadable.mutate(
{
path: { projectId: project.id, taskId: Number(task) },
content: { 'application/json': { addKeys: selection } },
},
{
onSuccess() {
messageService.success(t('batch_operations_add_task_keys_success'));
onFinished();
},
}
);
}

return (
<OperationContainer>
<TextField
minHeight={false}
value={task}
onChange={(e) => setTask(Number(e.currentTarget.value))}
/>
<BatchOperationsSubmit
disabled={disabled}
onClick={handleAddKeys}
loading={addTaskKeysLoadable.isLoading}
/>
</OperationContainer>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ const StyledActions = styled('div')`

type Props = OperationProps;

export const OperationCreateTask = ({ disabled, onClose }: Props) => {
export const OperationTaskCreate = ({ disabled, onFinished }: Props) => {
const project = useProject();
const { t } = useTranslate();
const [dialogOpen, setDialogOpen] = useState(true);
Expand Down Expand Up @@ -146,7 +146,7 @@ export const OperationCreateTask = ({ disabled, onClose }: Props) => {
params={{ count: values.languages.length }}
/>
);
onClose();
onFinished();
},
}
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { useState } from 'react';
import { useTranslate } from '@tolgee/react';

import { useApiMutation } from 'tg.service/http/useQueryApi';
import { useProject } from 'tg.hooks/useProject';
import { TextField } from 'tg.component/common/TextField';

import { useTranslationsSelector } from '../context/TranslationsContext';
import { OperationContainer } from './components/OperationContainer';
import { BatchOperationsSubmit } from './components/BatchOperationsSubmit';
import { OperationProps } from './types';
import { messageService } from 'tg.service/MessageService';
import { usePrefilter } from '../prefilters/usePrefilter';

type Props = OperationProps;

export const OperationTaskRemoveKeys = ({ disabled, onFinished }: Props) => {
const prefilter = usePrefilter();
const [task, setTask] = useState(prefilter.task ? prefilter.task : undefined);
const project = useProject();
const { t } = useTranslate();

const selection = useTranslationsSelector((c) => c.selection);

const addTaskKeysLoadable = useApiMutation({
url: '/v2/projects/{projectId}/tasks/{taskId}/keys',
method: 'put',
});

function handleAddKeys() {
addTaskKeysLoadable.mutate(
{
path: { projectId: project.id, taskId: Number(task) },
content: { 'application/json': { removeKeys: selection } },
},
{
onSuccess() {
messageService.success(
t('batch_operations_remove_task_keys_success')
);
onFinished();
},
}
);
}

return (
<OperationContainer>
<TextField
minHeight={false}
value={task}
onChange={(e) => setTask(Number(e.currentTarget.value))}
/>
<BatchOperationsSubmit
disabled={disabled}
onClick={handleAddKeys}
loading={addTaskKeysLoadable.isLoading}
/>
</OperationContainer>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ export type BatchActions =
| 'pre_translate'
| 'mark_as_reviewed'
| 'mark_as_translated'
| 'create_task'
| 'task_create'
| 'task_add_keys'
| 'task_remove_keys'
| 'add_tags'
| 'remove_tags'
| 'change_namespace'
Expand Down

0 comments on commit 5a165f4

Please sign in to comment.