Skip to content

Commit

Permalink
feat: tasks basic filters
Browse files Browse the repository at this point in the history
  • Loading branch information
stepan662 committed Jul 25, 2024
1 parent d958376 commit 2c3a278
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package io.tolgee.api.v2.controllers
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.tags.Tag
import io.tolgee.dtos.request.task.*
import io.tolgee.dtos.request.translation.GetTranslationsParams
import io.tolgee.dtos.request.translation.TranslationFilters
import io.tolgee.hateoas.task.TaskModel
import io.tolgee.hateoas.task.TaskModelAssembler
import io.tolgee.hateoas.userAccount.UserAccountInProjectModel
Expand All @@ -20,9 +22,12 @@ import io.tolgee.service.TaskService
import io.tolgee.service.security.UserAccountService
import jakarta.validation.Valid
import org.springdoc.core.annotations.ParameterObject
import org.springframework.beans.propertyeditors.CustomCollectionEditor
import org.springframework.data.domain.PageRequest
import org.springframework.data.domain.Pageable
import org.springframework.data.web.PagedResourcesAssembler
import org.springframework.hateoas.PagedModel
import org.springframework.web.bind.WebDataBinder
import org.springframework.web.bind.annotation.*

@RestController
Expand All @@ -49,12 +54,14 @@ class TaskController(
@UseDefaultPermissions
@AllowApiAccess
fun getTasks(
@ParameterObject
filters: TaskFilters,
@ParameterObject
pageable: Pageable,
@RequestParam("search", required = false)
search: String?,
): PagedModel<TaskModel> {
val tasks = taskService.getAllPaged(projectHolder.projectEntity, pageable, search)
val tasks = taskService.getAllPaged(projectHolder.projectEntity, pageable, search, filters)
return pagedTaskResourcesAssembler.toModel(tasks, taskModelAssembler)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.tolgee.dtos.request.task

import io.swagger.v3.oas.annotations.Parameter
import io.swagger.v3.oas.annotations.media.ExampleObject
import io.tolgee.model.enums.TaskState

open class TaskFilters {
@field:Parameter(
description = """Filter tasks with the state""",
)
var filterState: List<TaskState>? = null

@field:Parameter(
description = """Filter tasks without the state""",
)
var filterNotState: List<TaskState>? = null
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ package io.tolgee.model.enums
enum class TaskState {
IN_PROGRESS,
DONE,
CLOSED,
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.tolgee.repository

import io.tolgee.dtos.request.task.TaskFilters
import io.tolgee.model.Project
import io.tolgee.model.task.Task
import io.tolgee.model.task.TaskId
Expand All @@ -17,17 +18,28 @@ interface TaskRepository : JpaRepository<Task, TaskId> {
"""
select t
from Task t
where t.project.id = :projectId and
(
where
t.project.id = :projectId
and (
lower(t.name) like lower(concat('%', cast(:search as text),'%'))
or cast(:search as text) is null
)
and (
cast(:#{#filters.filterNotState} as text) is null
or t.state not in :#{#filters.filterNotState}
)
and (
cast(:#{#filters.filterState} as text) is null
or t.state in :#{#filters.filterState}
)
""",
)
fun getAllByProjectId(
projectId: Long,
pageable: Pageable,
search: String?,
filters: TaskFilters
): Page<Task>

@Query(
Expand Down
5 changes: 3 additions & 2 deletions backend/data/src/main/kotlin/io/tolgee/service/TaskService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,10 @@ class TaskService(
fun getAllPaged(
project: Project,
pageable: Pageable,
search: String?
search: String?,
filters: TaskFilters
): Page<TaskWithScopeView> {
val pagedTasks = taskRepository.getAllByProjectId(project.id, pageable, search)
val pagedTasks = taskRepository.getAllByProjectId(project.id, pageable, search, filters)
val withPrefetched = taskRepository.getByIdsWithAllPrefetched(pagedTasks.content)
return PageImpl(getTasksWithScope(withPrefetched), pageable, pagedTasks.totalElements)
}
Expand Down
61 changes: 33 additions & 28 deletions webapp/src/service/apiSchema.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1359,7 +1359,7 @@ export interface components {
*/
dueDate?: number;
assignees?: number[];
state?: "IN_PROGRESS" | "DONE";
state?: "IN_PROGRESS" | "DONE" | "CLOSED";
};
SimpleUserAccountModel: {
/** Format: int64 */
Expand Down Expand Up @@ -1390,7 +1390,7 @@ export interface components {
createdAt: number;
/** Format: int64 */
closedAt?: number;
state: "IN_PROGRESS" | "DONE";
state: "IN_PROGRESS" | "DONE" | "CLOSED";
};
AutoTranslationSettingsDto: {
/** Format: int64 */
Expand Down Expand Up @@ -2040,10 +2040,10 @@ export interface components {
convertPlaceholdersToIcu: boolean;
};
ImportSettingsModel: {
/** @description If true, key descriptions will be overridden by the import */
overrideKeyDescriptions: boolean;
/** @description If true, placeholders from other formats will be converted to ICU when possible */
convertPlaceholdersToIcu: boolean;
/** @description If true, key descriptions will be overridden by the import */
overrideKeyDescriptions: boolean;
};
TranslationCommentModel: {
/**
Expand Down Expand Up @@ -2200,14 +2200,14 @@ export interface components {
};
RevealedPatModel: {
token: string;
/** Format: int64 */
id: number;
description: string;
/** Format: int64 */
createdAt: number;
id: number;
/** Format: int64 */
updatedAt: number;
/** Format: int64 */
createdAt: number;
/** Format: int64 */
expiresAt?: number;
/** Format: int64 */
lastUsedAt?: number;
Expand Down Expand Up @@ -2346,17 +2346,17 @@ export interface components {
RevealedApiKeyModel: {
/** @description Resulting user's api key */
key: string;
description: string;
/** Format: int64 */
id: number;
projectName: string;
userFullName?: string;
description: string;
username?: string;
/** Format: int64 */
projectId: number;
/** Format: int64 */
expiresAt?: number;
/** Format: int64 */
projectId: number;
/** Format: int64 */
lastUsedAt?: number;
scopes: string[];
};
Expand Down Expand Up @@ -2433,7 +2433,7 @@ export interface components {
languageId: number;
assignees: number[];
keys: number[];
state?: "IN_PROGRESS" | "DONE";
state?: "IN_PROGRESS" | "DONE" | "CLOSED";
};
CalculateScopeRequest: {
/** Format: int64 */
Expand Down Expand Up @@ -3373,7 +3373,7 @@ export interface components {
createdAt: number;
/** Format: int64 */
closedAt?: number;
state: "IN_PROGRESS" | "DONE";
state: "IN_PROGRESS" | "DONE" | "CLOSED";
project: components["schemas"]["SimpleProjectModel"];
};
UserPreferencesModel: {
Expand Down Expand Up @@ -3496,22 +3496,22 @@ export interface components {
| "SLACK_INTEGRATION"
)[];
quickStart?: components["schemas"]["QuickStartModel"];
/** @example This is a beautiful organization full of beautiful and clever people */
description?: string;
/** @example Beautiful organization */
name: string;
/** Format: int64 */
id: number;
basePermissions: components["schemas"]["PermissionModel"];
/** @example This is a beautiful organization full of beautiful and clever people */
description?: string;
/**
* @description The role of currently authorized user.
*
* Can be null when user has direct access to one of the projects owned by the organization.
*/
currentUserRole?: "MEMBER" | "OWNER";
avatar?: components["schemas"]["Avatar"];
/** @example btforg */
slug: string;
avatar?: components["schemas"]["Avatar"];
};
PublicBillingConfigurationDTO: {
enabled: boolean;
Expand Down Expand Up @@ -3572,9 +3572,9 @@ export interface components {
defaultFileStructureTemplate: string;
};
DocItem: {
description?: string;
name: string;
displayName?: string;
description?: string;
};
PagedModelProjectModel: {
_embedded?: {
Expand Down Expand Up @@ -3651,23 +3651,23 @@ export interface components {
formalitySupported: boolean;
};
KeySearchResultView: {
description?: string;
name: string;
/** Format: int64 */
id: number;
namespace?: string;
description?: string;
baseTranslation?: string;
translation?: string;
baseTranslation?: string;
namespace?: string;
};
KeySearchSearchResultModel: {
view?: components["schemas"]["KeySearchResultView"];
description?: string;
name: string;
/** Format: int64 */
id: number;
namespace?: string;
description?: string;
baseTranslation?: string;
translation?: string;
baseTranslation?: string;
namespace?: string;
};
PagedModelKeySearchSearchResultModel: {
_embedded?: {
Expand Down Expand Up @@ -4213,14 +4213,14 @@ export interface components {
};
PatWithUserModel: {
user: components["schemas"]["SimpleUserAccountModel"];
/** Format: int64 */
id: number;
description: string;
/** Format: int64 */
createdAt: number;
id: number;
/** Format: int64 */
updatedAt: number;
/** Format: int64 */
createdAt: number;
/** Format: int64 */
expiresAt?: number;
/** Format: int64 */
lastUsedAt?: number;
Expand Down Expand Up @@ -4340,17 +4340,17 @@ export interface components {
* @description Languages for which user has translate permission.
*/
permittedLanguageIds?: number[];
description: string;
/** Format: int64 */
id: number;
projectName: string;
userFullName?: string;
description: string;
username?: string;
/** Format: int64 */
projectId: number;
/** Format: int64 */
expiresAt?: number;
/** Format: int64 */
projectId: number;
/** Format: int64 */
lastUsedAt?: number;
scopes: string[];
};
Expand Down Expand Up @@ -10516,6 +10516,10 @@ export interface operations {
/** Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */
sort?: string[];
search?: string;
/** Filter tasks with the state */
filterState?: ("IN_PROGRESS" | "DONE" | "CLOSED")[];
/** Filter tasks without the state */
filterNotState?: ("IN_PROGRESS" | "DONE" | "CLOSED")[];
};
path: {
projectId: number;
Expand Down Expand Up @@ -13480,6 +13484,7 @@ export interface operations {
size?: number;
/** Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */
sort?: string[];
search?: string;
};
};
responses: {
Expand Down
12 changes: 11 additions & 1 deletion webapp/src/views/projects/tasks/ProjectTasksView.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useState } from 'react';
import { Dialog, ListProps, PaperProps, styled } from '@mui/material';
import { Checkbox, Dialog, ListProps, PaperProps, styled } from '@mui/material';
import { useTranslate } from '@tolgee/react';

import { useProject } from 'tg.hooks/useProject';
Expand All @@ -24,6 +24,8 @@ export const ProjectTasksView = () => {
const project = useProject();
const { t } = useTranslate();
const [page, setPage] = useState(0);
const [search, setSearch] = useState('');
const [showClosed, setShowClosed] = useState(false);

const [detail, setDetail] = useState<TaskModel>();

Expand All @@ -38,6 +40,8 @@ export const ProjectTasksView = () => {
query: {
size: 20,
page,
search,
filterNotState: showClosed ? undefined : ['CLOSED', 'DONE'],
},
options: {
keepPreviousData: true,
Expand All @@ -58,9 +62,15 @@ export const ProjectTasksView = () => {
],
]}
>
<Checkbox
checked={showClosed}
onChange={(e) => setShowClosed(e.target.checked)}
/>
<PaginatedHateoasList
loadable={tasksLoadable}
onPageChange={setPage}
searchText={search}
onSearchChange={setSearch}
listComponentProps={
{
sx: {
Expand Down

0 comments on commit 2c3a278

Please sign in to comment.