Skip to content

Commit

Permalink
feat: update dashboard
Browse files Browse the repository at this point in the history
  • Loading branch information
stepan662 committed Sep 19, 2024
1 parent 2482e33 commit 5648505
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,21 @@ 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.TaskFilters
import io.tolgee.hateoas.project.stats.LanguageStatsModelAssembler
import io.tolgee.hateoas.project.stats.ProjectStatsModel
import io.tolgee.model.enums.Scope
import io.tolgee.model.enums.TaskState
import io.tolgee.security.ProjectHolder
import io.tolgee.security.authentication.AllowApiAccess
import io.tolgee.security.authorization.RequiresProjectPermissions
import io.tolgee.security.authorization.UseDefaultPermissions
import io.tolgee.service.TaskService
import io.tolgee.service.language.LanguageService
import io.tolgee.service.project.LanguageStatsService
import io.tolgee.service.project.ProjectService
import io.tolgee.service.project.ProjectStatsService
import org.springframework.data.domain.Pageable
import org.springframework.hateoas.MediaTypes
import org.springframework.web.bind.annotation.CrossOrigin
import org.springframework.web.bind.annotation.GetMapping
Expand All @@ -36,6 +40,7 @@ class ProjectStatsController(
private val languageStatsService: LanguageStatsService,
private val languageStatsModelAssembler: LanguageStatsModelAssembler,
private val languageService: LanguageService,
private val taskService: TaskService,
) {
@Operation(summary = "Get project stats")
@GetMapping("", produces = [MediaTypes.HAL_JSON_VALUE])
Expand All @@ -62,6 +67,7 @@ class ProjectStatsController(
projectId = projectStats.id,
languageCount = languageStats.size,
keyCount = projectStats.keyCount,
taskCount = projectStats.taskCount,
baseWordsCount = totals.baseWordsCount,
translatedPercentage = totals.translatedPercent,
reviewedPercentage = totals.reviewedPercent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ open class ProjectStatsModel(
val projectId: Long,
val languageCount: Int,
val keyCount: Long,
val taskCount: Long,
val baseWordsCount: Long,
val translatedPercentage: Double,
val reviewedPercentage: Double,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ data class ProjectStatsView(
val keyCount: Long,
val memberCount: Long,
val tagCount: Long,
val taskCount: Long
)
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ import io.tolgee.model.Project
import io.tolgee.model.Project_
import io.tolgee.model.UserAccount
import io.tolgee.model.UserAccount_
import io.tolgee.model.enums.TaskState
import io.tolgee.model.key.Key
import io.tolgee.model.key.Key_
import io.tolgee.model.key.Tag
import io.tolgee.model.key.Tag_
import io.tolgee.model.task.Task
import io.tolgee.model.task.Task_
import io.tolgee.model.views.projectStats.ProjectStatsView
import io.tolgee.util.KotlinCriteriaBuilder
import jakarta.persistence.EntityManager
Expand All @@ -36,6 +39,7 @@ open class ProjectStatsProvider(
getKeyCountSelection(),
getMemberCountSelection(),
getTagSelection(),
getTaskCountSelection()
)

query.multiselect(selection)
Expand Down Expand Up @@ -66,7 +70,6 @@ open class ProjectStatsProvider(
val permissionJoin = subProject.join(Project_.permissions, JoinType.LEFT)
val organizationJoin = subProject.join(Project_.organizationOwner, JoinType.LEFT)
val rolesJoin = organizationJoin.join(Organization_.memberRoles, JoinType.LEFT)

sub.where(
project equal subProject and
(
Expand All @@ -76,4 +79,12 @@ open class ProjectStatsProvider(
)
return sub.select(cb.countDistinct(subUserAccount.get(UserAccount_.id)))
}

private fun getTaskCountSelection(): Selection<Long> {
val sub = query.subquery(Long::class.java)
val task = sub.from(Task::class.java)
sub.where(task.get(Task_.project) equal project)
sub.where(task.get(Task_.state).`in`(listOf(TaskState.NEW, TaskState.IN_PROGRESS)))
return sub.select(cb.coalesce(cb.countDistinct(task.get(Tag_.id)), 0))
}
}
102 changes: 56 additions & 46 deletions webapp/src/service/apiSchema.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1085,6 +1085,10 @@ export interface components {
| "slack_workspace_already_connected"
| "slack_connection_error"
| "email_verification_code_not_valid"
| "cannot_subscribe_to_free_plan"
| "plan_auto_assignment_only_for_free_plans"
| "plan_auto_assignment_only_for_private_plans"
| "plan_auto_assignment_organization_ids_not_in_for_organization_ids"
| "task_not_found"
| "task_not_finished"
| "task_not_open";
Expand Down Expand Up @@ -1160,21 +1164,11 @@ export interface components {
| "SERVER_ADMIN";
/** @description The user's permission type. This field is null if uses granular permissions */
type?: "NONE" | "VIEW" | "TRANSLATE" | "REVIEW" | "EDIT" | "MANAGE";
/**
* @description List of languages user can translate to. If null, all languages editing is permitted.
* @example 200001,200004
*/
translateLanguageIds?: number[];
/**
* @description List of languages user can view. If null, all languages view is permitted.
* @example 200001,200004
*/
viewLanguageIds?: number[];
/**
* @description List of languages user can change state to. If null, changing state of all language values is permitted.
* @example 200001,200004
*/
stateChangeLanguageIds?: number[];
/**
* @description Granted scopes to the user. When user has type permissions, this field contains permission scopes of the type.
* @example KEYS_EDIT,TRANSLATIONS_VIEW
Expand Down Expand Up @@ -1209,6 +1203,16 @@ export interface components {
| "tasks.view"
| "tasks.edit"
)[];
/**
* @description List of languages user can translate to. If null, all languages editing is permitted.
* @example 200001,200004
*/
translateLanguageIds?: number[];
/**
* @description List of languages user can change state to. If null, changing state of all language values is permitted.
* @example 200001,200004
*/
stateChangeLanguageIds?: number[];
/**
* @deprecated
* @description Deprecated (use translateLanguageIds).
Expand Down Expand Up @@ -2071,12 +2075,12 @@ export interface components {
createNewKeys: boolean;
};
ImportSettingsModel: {
/** @description If false, only updates keys, skipping the creation of new keys */
createNewKeys: 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;
/** @description If false, only updates keys, skipping the creation of new keys */
createNewKeys: boolean;
};
TranslationCommentModel: {
/**
Expand Down Expand Up @@ -2233,17 +2237,17 @@ export interface components {
};
RevealedPatModel: {
token: string;
description: string;
/** Format: int64 */
id: number;
/** Format: int64 */
expiresAt?: number;
/** Format: int64 */
lastUsedAt?: number;
/** Format: int64 */
createdAt: number;
/** Format: int64 */
updatedAt: number;
/** Format: int64 */
expiresAt?: number;
/** Format: int64 */
lastUsedAt?: number;
description: string;
};
SetOrganizationRoleDto: {
roleType: "MEMBER" | "OWNER";
Expand Down Expand Up @@ -2379,19 +2383,19 @@ export interface components {
RevealedApiKeyModel: {
/** @description Resulting user's api key */
key: string;
description: string;
/** Format: int64 */
id: number;
/** Format: int64 */
projectId: number;
userFullName?: string;
projectName: string;
username?: string;
/** Format: int64 */
expiresAt?: number;
scopes: string[];
/** Format: int64 */
projectId: number;
/** Format: int64 */
lastUsedAt?: number;
username?: string;
scopes: string[];
projectName: string;
userFullName?: string;
description: string;
};
SuperTokenRequest: {
/** @description Has to be provided when TOTP enabled */
Expand Down Expand Up @@ -2466,7 +2470,6 @@ export interface components {
languageId: number;
assignees: number[];
keys: number[];
state?: "NEW" | "IN_PROGRESS" | "DONE" | "CLOSED";
};
CalculateScopeRequest: {
/** Format: int64 */
Expand All @@ -2476,11 +2479,11 @@ export interface components {
};
KeysScopeView: {
/** Format: int64 */
wordCount: number;
characterCount: number;
/** Format: int64 */
keyCount: number;
/** Format: int64 */
characterCount: number;
wordCount: number;
};
GetKeysRequestDto: {
keys: components["schemas"]["KeyDefinitionDto"][];
Expand Down Expand Up @@ -2818,6 +2821,10 @@ export interface components {
| "slack_workspace_already_connected"
| "slack_connection_error"
| "email_verification_code_not_valid"
| "cannot_subscribe_to_free_plan"
| "plan_auto_assignment_only_for_free_plans"
| "plan_auto_assignment_only_for_private_plans"
| "plan_auto_assignment_organization_ids_not_in_for_organization_ids"
| "task_not_found"
| "task_not_finished"
| "task_not_open";
Expand Down Expand Up @@ -3185,6 +3192,7 @@ export interface components {
isPlural?: boolean;
/** @description List of services to use. If null, then all enabled services are used. */
services?: ("GOOGLE" | "AWS" | "DEEPL" | "AZURE" | "BAIDU" | "TOLGEE")[];
plural?: boolean;
};
PagedModelTranslationMemoryItemModel: {
_embedded?: {
Expand Down Expand Up @@ -3537,8 +3545,6 @@ 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 */
Expand All @@ -3553,6 +3559,8 @@ export interface components {
avatar?: components["schemas"]["Avatar"];
/** @example btforg */
slug: string;
/** @example This is a beautiful organization full of beautiful and clever people */
description?: string;
};
PublicBillingConfigurationDTO: {
enabled: boolean;
Expand Down Expand Up @@ -3613,9 +3621,9 @@ export interface components {
defaultFileStructureTemplate: string;
};
DocItem: {
description?: string;
name: string;
displayName?: string;
description?: string;
};
PagedModelProjectModel: {
_embedded?: {
Expand Down Expand Up @@ -3710,23 +3718,23 @@ export interface components {
formalitySupported: boolean;
};
KeySearchResultView: {
description?: string;
name: string;
/** Format: int64 */
id: number;
baseTranslation?: string;
translation?: string;
namespace?: string;
description?: string;
translation?: string;
};
KeySearchSearchResultModel: {
view?: components["schemas"]["KeySearchResultView"];
description?: string;
name: string;
/** Format: int64 */
id: number;
baseTranslation?: string;
translation?: string;
namespace?: string;
description?: string;
translation?: string;
};
PagedModelKeySearchSearchResultModel: {
_embedded?: {
Expand Down Expand Up @@ -4205,6 +4213,8 @@ export interface components {
/** Format: int64 */
keyCount: number;
/** Format: int64 */
taskCount: number;
/** Format: int64 */
baseWordsCount: number;
/** Format: double */
translatedPercentage: number;
Expand Down Expand Up @@ -4290,17 +4300,17 @@ export interface components {
};
PatWithUserModel: {
user: components["schemas"]["SimpleUserAccountModel"];
description: string;
/** Format: int64 */
id: number;
/** Format: int64 */
expiresAt?: number;
/** Format: int64 */
lastUsedAt?: number;
/** Format: int64 */
createdAt: number;
/** Format: int64 */
updatedAt: number;
/** Format: int64 */
expiresAt?: number;
/** Format: int64 */
lastUsedAt?: number;
description: string;
};
PagedModelOrganizationModel: {
_embedded?: {
Expand Down Expand Up @@ -4417,19 +4427,19 @@ export interface components {
* @description Languages for which user has translate permission.
*/
permittedLanguageIds?: number[];
description: string;
/** Format: int64 */
id: number;
/** Format: int64 */
projectId: number;
userFullName?: string;
projectName: string;
username?: string;
/** Format: int64 */
expiresAt?: number;
scopes: string[];
/** Format: int64 */
projectId: number;
/** Format: int64 */
lastUsedAt?: number;
username?: string;
scopes: string[];
projectName: string;
userFullName?: string;
description: string;
};
PagedModelUserAccountModel: {
_embedded?: {
Expand Down
2 changes: 1 addition & 1 deletion webapp/src/views/projects/dashboard/ActivityList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export const ActivityList: React.FC<Props> = ({ activityLoadable }) => {
return (
<StyledContainer>
<StyledHeader>
<Typography variant="h5">
<Typography variant="h4">
<T keyName="dashboard_activity_title" />
</Typography>
<FormControlLabel
Expand Down
Loading

0 comments on commit 5648505

Please sign in to comment.