Skip to content

Commit

Permalink
fix: more queries performance
Browse files Browse the repository at this point in the history
  • Loading branch information
LamaEats committed Nov 25, 2024
1 parent df8f338 commit d0bc0ca
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 33 deletions.
2 changes: 1 addition & 1 deletion src/components/OfflineBanner/OfflineBanner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { OfflineBanner as OfflineBannerBricks } from '@taskany/bricks/harmony';
import { tr } from './OfflineBanner.i18n';

export const OfflineBanner = () => {
const isOnline = useRef<boolean | null>(null);
const isOnline = useRef<boolean | null>(true);

// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [_, remoteServerStatus] = useOfflineDetector({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,16 @@ import { FC, ComponentProps, useMemo, useState, useEffect } from 'react';
import { nullable } from '@taskany/bricks';
import { TreeViewElement } from '@taskany/bricks/harmony';

import { FilterById } from '../../../trpc/inferredTypes';
import { FilterById, ProjectChildrenTree } from '../../../trpc/inferredTypes';
import { useUrlFilterParams } from '../../hooks/useUrlFilterParams';
import { routes } from '../../hooks/router';
import { ProjectListItemCollapsable } from '../ProjectListItemCollapsable/ProjectListItemCollapsable';
import { ProjectGoalList } from '../ProjectGoalList/ProjectGoalList';
import { Kanban } from '../Kanban/Kanban';
import { ProjectTree } from '../../../trpc/router/projectV2';

interface ProjectListItemConnectedProps extends ComponentProps<typeof ProjectListItemCollapsable> {
parent?: ComponentProps<typeof ProjectListItemCollapsable>['project'];
subTree?: ProjectTree[string] | null;
subTree?: ProjectChildrenTree[string] | null;
partnershipProject?: string[];
filterPreset?: FilterById;
mainProject?: boolean;
Expand All @@ -26,7 +25,7 @@ const onProjectClickHandler = (e: React.MouseEvent) => {
}
};

const getIsProjectEmptySetter = (subTree?: ProjectTree[string] | null) => () => {
const getIsProjectEmptySetter = (subTree?: ProjectChildrenTree[string] | null) => () => {
if (subTree) {
if (Number(subTree.count) > 0) return false;

Expand Down
50 changes: 33 additions & 17 deletions src/components/ProjectPage/ProjectPage.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { useCallback, useEffect, useMemo } from 'react';
import { useCallback, useDeferredValue, useEffect, useMemo } from 'react';
import NextLink from 'next/link';
import { nullable } from '@taskany/bricks';
import { ListView, Breadcrumb, Breadcrumbs, Link, FiltersBarItem } from '@taskany/bricks/harmony';

import { Page } from '../Page/Page';
import { GoalByIdReturnType } from '../../../trpc/inferredTypes';
import { refreshInterval } from '../../utils/config';
import { GoalByIdReturnType, ProjectChildrenTree } from '../../../trpc/inferredTypes';
import { routes } from '../../hooks/router';
import { ExternalPageProps } from '../../utils/declareSsrProps';
import { useUrlFilterParams } from '../../hooks/useUrlFilterParams';
Expand All @@ -23,6 +22,29 @@ import s from './ProjectPage.module.css';

export const projectsSize = 20;

const countAvailableGoals = (subTree?: ProjectChildrenTree[string] | null) => {
let count = 0;
if (subTree) {
const nodes = [subTree.children];
let i = 0;
let current = nodes[0];
while (current) {
const keys = Object.keys(current);
for (const key of keys) {
count += current[key].count || 0;

if (current[key].children) {
nodes.push(current[key].children);
}
}
i++;
current = nodes[i];
}
}

return count;
};

export const ProjectPage = ({ user, ssrTime, params: { id }, defaultPresetFallback }: ExternalPageProps) => {
const utils = trpc.useContext();

Expand All @@ -32,35 +54,29 @@ export const ProjectPage = ({ user, ssrTime, params: { id }, defaultPresetFallba
preset,
});

const [projectQuery, projectDeepInfoQuery, projectTreeQuery] = trpc.useQueries((ctx) => [
const [projectQuery, projectTreeQuery] = trpc.useQueries((ctx) => [
ctx.v2.project.getById({ id }, { enabled: Boolean(id) }),
ctx.v2.project.getProjectGoalsById(
{ id, goalsQuery: queryState },
{
keepPreviousData: true,
staleTime: refreshInterval,
enabled: Boolean(id),
},
),
ctx.v2.project.getProjectChildrenTree(
{
id,
goalsQuery: queryState,
},
{
keepPreviousData: true,
staleTime: refreshInterval,
staleTime: Infinity,
enabled: Boolean(id),
},
),
]);

const wholeGoalCountValue = useDeferredValue(countAvailableGoals(projectTreeQuery.data?.[id]));

const { setPreview, on } = useGoalPreview();

const invalidateFnsCallback = useCallback(() => {
utils.v2.project.getById.invalidate();
utils.v2.project.getProjectGoalsById.invalidate();
}, [utils.v2.project.getProjectGoalsById, utils.v2.project.getById]);
utils.v2.project.getProjectChildrenTree.invalidate();
}, [utils.v2.project.getProjectChildrenTree, utils.v2.project.getById]);

useEffect(() => {
const unsubUpdate = on('on:goal:update', invalidateFnsCallback);
Expand Down Expand Up @@ -95,8 +111,8 @@ export const ProjectPage = ({ user, ssrTime, params: { id }, defaultPresetFallba
header={
<FiltersPanel
title={ctx.project?.title || tr('Projects')}
total={ctx.project?._count?.goals ?? 0}
counter={projectDeepInfoQuery.data?.goals?.length}
counter={ctx.project?._count?.goals ?? 0}
total={wholeGoalCountValue}
filterPreset={preset}
enableLayoutToggle
enableHideProjectToggle
Expand Down
1 change: 1 addition & 0 deletions trpc/inferredTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export type StateType = State['type'];
export type DashboardProjectV2 = RouterOutputs['v2']['project']['getUserDashboardProjects']['groups'][number];
export type DashboardGoalV2 = NonNullable<DashboardProjectV2['goals']>[number];
export type ProjectByIdReturnTypeV2 = RouterOutputs['v2']['project']['getById'];
export type ProjectChildrenTree = RouterOutputs['v2']['project']['getProjectChildrenTree'];

export type GoalActivityHistory = RouterOutputs['goal']['getGoalActivityFeed'];
export type GoalComments = RouterOutputs['goal']['getGoalCommentsFeed'];
Expand Down
25 changes: 14 additions & 11 deletions trpc/queries/projectV2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -802,13 +802,16 @@ export const getProjectChildrenTreeQuery = ({ id, goalsQuery }: { id: string; go
.leftJoinLateral(
({ selectFrom }) =>
selectFrom('Goal')
.selectAll('Goal')
.select(({ fn }) => fn.count('Goal.id').as('goal_count'))
.leftJoinLateral(
() => getUserActivity().as('participant'),
(join) =>
join.onRef('participant.id', 'in', (qb) =>
qb.selectFrom('_goalParticipants').select('A').whereRef('B', '=', 'Goal.id'),
),
() =>
getUserActivity()
.whereRef('Activity.id', 'in', (qb) =>
// @ts-ignore
qb.selectFrom('_goalParticipants').select('A').whereRef('B', '=', 'Goal.id'),
)
.as('participant'),
(join) => join.onTrue(),
)
.leftJoinLateral(
({ selectFrom }) =>
Expand All @@ -823,16 +826,16 @@ export const getProjectChildrenTreeQuery = ({ id, goalsQuery }: { id: string; go
.where('Goal.archived', 'is not', true)
.where(getGoalsFiltersWhereExpressionBuilder(goalsQuery))
.as('goal'),
(join) => join.onRef('goal.projectId', '=', 'Project.id'),
(join) => join.onTrue(),
)
.select(({ fn, cast }) => [
.select(({ cast, ref }) => [
'Project.id',
'Project.title',
cast(fn.count('goal.id'), 'integer').as('goal_count'),
sql`to_json(ch.parent_chain)`.as('chain'),
cast(ref('goal.goal_count'), 'integer').as('goal_count'),
'ch.parent_chain as chain',
'ch.level as deep',
])
.groupBy(['Project.id', 'ch.level', 'ch.parent_chain'])
.groupBy(['Project.id', 'ch.level', 'ch.parent_chain', 'goal.goal_count'])
.orderBy('ch.level asc');
};

Expand Down

0 comments on commit d0bc0ca

Please sign in to comment.