diff --git a/src/components/DashboardPage/DashboardPage.tsx b/src/components/DashboardPage/DashboardPage.tsx
index f2959fc21..01c8b30e9 100644
--- a/src/components/DashboardPage/DashboardPage.tsx
+++ b/src/components/DashboardPage/DashboardPage.tsx
@@ -23,7 +23,7 @@ import { tr } from './DashboardPage.i18n';
export const DashboardPage = ({ user, ssrTime, defaultPresetFallback }: ExternalPageProps) => {
const { preset } = useFiltersPreset({ defaultPresetFallback });
- const { currentPreset, queryState } = useUrlFilterParams({
+ const { currentPreset, queryState, projectsSort } = useUrlFilterParams({
preset,
});
@@ -33,6 +33,7 @@ export const DashboardPage = ({ user, ssrTime, defaultPresetFallback }: External
...queryState,
limit: 10,
},
+ projectsSort,
},
{
getNextPageParam: ({ pagination }) => pagination.offset,
@@ -85,6 +86,7 @@ export const DashboardPage = ({ user, ssrTime, defaultPresetFallback }: External
counter={goalsCount}
filterPreset={preset}
enableLayoutToggle
+ enableProjectsSort
enableHideProjectToggle
/>
}
diff --git a/src/components/FiltersPanel/FiltersPanel.i18n/en.json b/src/components/FiltersPanel/FiltersPanel.i18n/en.json
index e5659f513..6e84d6fbe 100644
--- a/src/components/FiltersPanel/FiltersPanel.i18n/en.json
+++ b/src/components/FiltersPanel/FiltersPanel.i18n/en.json
@@ -7,7 +7,8 @@
"Estimate": "Estimate",
"Limit": "Limit",
"Preset": "Preset",
- "Sort": "Sort",
+ "Goals sort": "Goals sort",
+ "Projects sort": "Projects sort",
"Issuer": "Issuer",
"Participant": "Participant",
"Filter": "Filter",
diff --git a/src/components/FiltersPanel/FiltersPanel.i18n/ru.json b/src/components/FiltersPanel/FiltersPanel.i18n/ru.json
index c38778dd0..02294d6ca 100644
--- a/src/components/FiltersPanel/FiltersPanel.i18n/ru.json
+++ b/src/components/FiltersPanel/FiltersPanel.i18n/ru.json
@@ -7,7 +7,8 @@
"Estimate": "Срок",
"Limit": "Лимит",
"Preset": "Пресет",
- "Sort": "Сортировка",
+ "Goals sort": "Сортировка целей",
+ "Projects sort": "Сортировка проектов",
"Issuer": "Автор",
"Participant": "Участник",
"Filter": "Фильтр",
diff --git a/src/components/FiltersPanel/FiltersPanel.tsx b/src/components/FiltersPanel/FiltersPanel.tsx
index bb515da5d..052d092f7 100644
--- a/src/components/FiltersPanel/FiltersPanel.tsx
+++ b/src/components/FiltersPanel/FiltersPanel.tsx
@@ -10,7 +10,13 @@ import {
} from '@taskany/bricks/harmony';
import { nullable, useLatest } from '@taskany/bricks';
-import { FilterQueryState, QueryState, useUrlFilterParams } from '../../hooks/useUrlFilterParams';
+import {
+ FilterQueryState,
+ QueryState,
+ SortableGoalsProps,
+ SortableProjectsProps,
+ useUrlFilterParams,
+} from '../../hooks/useUrlFilterParams';
import { FilterById } from '../../../trpc/inferredTypes';
import {
filtersPanel,
@@ -52,8 +58,9 @@ export const FiltersPanel: FC<{
filterPreset?: FilterById;
enableViewToggle?: boolean;
enableLayoutToggle?: boolean;
- enableHideProjectToggle?: boolean;
children?: ReactNode;
+ enableHideProjectToggle?: boolean;
+ enableProjectsSort?: boolean;
}> = memo(
({
children,
@@ -62,6 +69,7 @@ export const FiltersPanel: FC<{
counter = 0,
enableViewToggle,
enableLayoutToggle,
+ enableProjectsSort,
enableHideProjectToggle,
filterPreset,
}) => {
@@ -72,8 +80,10 @@ export const FiltersPanel: FC<{
currentPreset,
queryString,
queryState,
+ projectsSort,
resetQueryState,
batchQueryState,
+ setProjectsSortFilter,
setSortFilter,
queryFilterState,
groupBy,
@@ -242,7 +252,7 @@ export const FiltersPanel: FC<{
>
))}
- {tr('Sort')}
+ {tr('Goals sort')}
key === k);
if (paramExistingIndex > -1) {
- sortParams[paramExistingIndex] = { key, dir };
+ sortParams[paramExistingIndex] = {
+ key: key as SortableGoalsProps,
+ dir,
+ };
} else {
- sortParams.push({ key, dir });
+ sortParams.push({ key: key as SortableGoalsProps, dir });
}
}
@@ -265,6 +278,39 @@ export const FiltersPanel: FC<{
}}
/>
+ {nullable(enableProjectsSort, () => (
+ <>
+ {tr('Projects sort')}
+
+ {
+ let sortParams = (projectsSort ?? []).slice();
+
+ if (!dir) {
+ sortParams = sortParams.filter(({ key: k }) => key !== k);
+ } else {
+ const paramExistingIndex = sortParams.findIndex(
+ ({ key: k }) => key === k,
+ );
+
+ if (paramExistingIndex > -1) {
+ sortParams[paramExistingIndex] = {
+ key: key as SortableProjectsProps,
+ dir,
+ };
+ } else {
+ sortParams.push({ key: key as SortableProjectsProps, dir });
+ }
+ }
+
+ setProjectsSortFilter(sortParams);
+ }}
+ />
+
+ >
+ ))}
{tr('Visibility')}
}
>
diff --git a/src/components/GroupedGoalList.tsx b/src/components/GroupedGoalList.tsx
index 9cf428c56..402059fa8 100644
--- a/src/components/GroupedGoalList.tsx
+++ b/src/components/GroupedGoalList.tsx
@@ -21,7 +21,7 @@ export const projectsSize = 20;
export const GroupedGoalList: React.FC = ({ filterPreset }) => {
const { setPreview, on } = useGoalPreview();
- const { queryState } = useUrlFilterParams({
+ const { queryState, projectsSort } = useUrlFilterParams({
preset: filterPreset,
});
@@ -31,6 +31,7 @@ export const GroupedGoalList: React.FC = ({ filterPreset }
limit: projectsSize,
goalsQuery: queryState,
firstLevel: !!queryState?.project?.length,
+ projectsSort,
},
{
getNextPageParam: ({ pagination }) => pagination.offset,
diff --git a/src/components/SortList/SortList.i18n/en.json b/src/components/SortList/SortList.i18n/en.json
index b519dee8e..fe4f257bc 100644
--- a/src/components/SortList/SortList.i18n/en.json
+++ b/src/components/SortList/SortList.i18n/en.json
@@ -6,5 +6,8 @@
"Activity": "Activity",
"Owner": "Owner",
"UpdatedAt": "Updated",
- "CreatedAt": "Created"
+ "CreatedAt": "Created",
+ "Stargizers": "Stargizers",
+ "Goals": "Goals",
+ "Watchers": "Watchers"
}
diff --git a/src/components/SortList/SortList.i18n/ru.json b/src/components/SortList/SortList.i18n/ru.json
index 250074ca5..0cfc060e6 100644
--- a/src/components/SortList/SortList.i18n/ru.json
+++ b/src/components/SortList/SortList.i18n/ru.json
@@ -6,5 +6,8 @@
"Activity": "Автор",
"Owner": "Ответственный",
"UpdatedAt": "Обновлено",
- "CreatedAt": "Создано"
+ "CreatedAt": "Создано",
+ "Stargizers": "В избранном",
+ "Goals": "Цели",
+ "Watchers": "Отслеживается"
}
diff --git a/src/components/SortList/SortList.tsx b/src/components/SortList/SortList.tsx
index ee04b89cd..e679de46b 100644
--- a/src/components/SortList/SortList.tsx
+++ b/src/components/SortList/SortList.tsx
@@ -1,52 +1,80 @@
import React, { useCallback, useMemo } from 'react';
import { AutoComplete, AutoCompleteList } from '@taskany/bricks/harmony';
-import type { FilterQueryState, SortableProps, SortDirection } from '../../hooks/useUrlFilterParams';
+import type {
+ FilterQueryState,
+ SortableBaseProps,
+ SortableGoalsProps,
+ SortableProjectsProps,
+ SortDirection,
+} from '../../hooks/useUrlFilterParams';
import { SortButton } from '../SortButton/SortButton';
import { tr } from './SortList.i18n';
import styles from './SortList.module.css';
-interface SortListProps {
- value?: FilterQueryState['sort'];
- onChange: (key: SortableProps, dir: SortDirection | null) => void;
+interface SortListProps {
+ variant?: 'goals' | 'projects';
+ value?: T;
+ onChange: (key: SortableGoalsProps | SortableProjectsProps, dir: SortDirection | null) => void;
}
interface SingleSortItem {
- id: SortableProps;
+ id: SortableGoalsProps | SortableProjectsProps;
title: string;
dir: SortDirection | null;
}
-export const SortList: React.FC = ({ value, onChange }) => {
+export const SortList = ({
+ variant = 'goals',
+ value,
+ onChange,
+}: SortListProps) => {
const { itemsToRender, sortItems } = useMemo(() => {
- const sortItems = {
+ const baseSortItems: Record = {
title: tr('Title'),
- state: tr('State'),
- priority: tr('Priority'),
- project: tr('Project'),
- activity: tr('Activity'),
owner: tr('Owner'),
updatedAt: tr('UpdatedAt'),
createdAt: tr('CreatedAt'),
};
+ const sortGoalsItems: Record, string> = {
+ state: tr('State'),
+ activity: tr('Activity'),
+ priority: tr('Priority'),
+ project: tr('Project'),
+ };
+
+ const sortProjectItems: Record, string> = {
+ stargizers: tr('Stargizers'),
+ watchers: tr('Watchers'),
+ goals: tr('Goals'),
+ };
+
+ const sortItems =
+ variant === 'goals' ? { ...baseSortItems, ...sortGoalsItems } : { ...baseSortItems, ...sortProjectItems };
return {
sortItems,
- itemsToRender: (Object.entries(sortItems) as Array<[SortableProps, string]>).map(([id, title]) => ({
+ itemsToRender: (
+ Object.entries(sortItems) as Array<[SortableGoalsProps | SortableProjectsProps, string]>
+ ).map(([id, title]) => ({
id,
title,
dir: null,
})),
};
- }, []);
+ }, [variant]);
const selected: SingleSortItem[] | undefined = useMemo(() => {
- return value?.map(({ key, dir }) => ({ id: key, title: sortItems[key], dir }));
+ return value?.map(({ key, dir }) => ({
+ id: key,
+ title: sortItems[key as SortableBaseProps],
+ dir,
+ }));
}, [value, sortItems]);
const handleChange = useCallback(
- (key: SortableProps) => (dir: SortDirection | null) => {
+ (key: SortableGoalsProps | SortableProjectsProps) => (dir: SortDirection | null) => {
onChange(key, dir);
},
[onChange],
diff --git a/src/hooks/useUrlFilterParams.ts b/src/hooks/useUrlFilterParams.ts
index 703a1c838..71194b671 100644
--- a/src/hooks/useUrlFilterParams.ts
+++ b/src/hooks/useUrlFilterParams.ts
@@ -3,11 +3,11 @@ import { ParsedUrlQuery } from 'querystring';
import { MouseEventHandler, useCallback, useMemo, useState } from 'react';
import { FilterById, StateType } from '../../trpc/inferredTypes';
-import { StateTypeEnum } from '../schema/common';
+import { SortableProjectsPropertiesArray, StateTypeEnum } from '../schema/common';
import { setCookie } from '../utils/cookies';
export type SortDirection = 'asc' | 'desc';
-export type SortableProps =
+export type SortableGoalsProps =
| 'title'
| 'state'
| 'priority'
@@ -17,6 +17,10 @@ export type SortableProps =
| 'updatedAt'
| 'createdAt';
+export type SortableProjectsProps = NonNullable[number]['key'];
+
+export type SortableBaseProps = SortableGoalsProps & SortableProjectsProps;
+
export const filtersNoSearchPresetCookie = 'taskany.NoSearchPreset';
// TODO: replace it with QueryWithFilters from schema/common
@@ -32,7 +36,8 @@ export interface FilterQueryState {
project: string[];
partnershipProject: string[];
query: string;
- sort: Array<{ key: SortableProps; dir: SortDirection }>;
+ sort: Array<{ key: SortableGoalsProps; dir: SortDirection }>;
+ projectsSort: NonNullable;
hideCriteria?: boolean;
hideEmptyProjects?: boolean;
}
@@ -86,16 +91,20 @@ export interface QueryState extends BaseQueryState, FilterQueryState {}
const parseQueryParam = (param = '') => param.split(',').filter(Boolean);
-const parseSortQueryParam = (param = '') =>
+const parseSortQueryParam = (param = '') =>
param.split(',').reduce((acc, curr) => {
if (curr) {
- const [key, dir] = curr.split(':') as [SortableProps, SortDirection];
- acc.push({ key, dir });
+ const [key, dir] = curr.split(':') as [
+ K extends 'goals' ? SortableGoalsProps : SortableProjectsProps,
+ SortDirection,
+ ];
+ acc.push({ key: key as SortableBaseProps, dir });
}
return acc;
- }, [] as QueryState['sort']);
+ }, [] as K extends 'goals' ? QueryState['sort'] : QueryState['projectsSort']);
-const stringifySortQueryParam = (param: QueryState['sort']) => param.map(({ key, dir }) => `${key}:${dir}`).join(',');
+const stringifySortQueryParam = (param: QueryState['sort' | 'projectsSort']) =>
+ param.map(({ key, dir }) => `${key}:${dir}`).join(',');
export const buildURLSearchParams = ({
priority = [],
@@ -112,6 +121,7 @@ export const buildURLSearchParams = ({
starred,
watching,
sort = [],
+ projectsSort = [],
groupBy,
view,
limit,
@@ -146,6 +156,10 @@ export const buildURLSearchParams = ({
sort.length > 0 ? urlParams.set('sort', stringifySortQueryParam(sort)) : urlParams.delete('sort');
+ projectsSort.length > 0
+ ? urlParams.set('projectsSort', stringifySortQueryParam(projectsSort))
+ : urlParams.delete('projectsSort');
+
query.length > 0 ? urlParams.set('query', query.toString()) : urlParams.delete('query');
starred ? urlParams.set('starred', '1') : urlParams.delete('starred');
@@ -190,7 +204,10 @@ export const parseFilterValues = (query: ParsedUrlQuery): FilterQueryState => {
if (query.partnershipProject) queryMap.partnershipProject = parseQueryParam(query.partnershipProject?.toString());
if (query.query) queryMap.query = parseQueryParam(query.query?.toString()).toString();
if (query.sort) {
- queryMap.sort = parseSortQueryParam(query.sort?.toString());
+ queryMap.sort = parseSortQueryParam<'goals'>(query.sort?.toString());
+ }
+ if (query.projectsSort) {
+ queryMap.projectsSort = parseSortQueryParam<'projects'>(query.projectsSort?.toString());
}
if (query.hideCriteria) queryMap.hideCriteria = Boolean(query.hideCriteria) || undefined;
if (query.hideEmptyProjects) queryMap.hideEmptyProjects = Boolean(query.hideEmptyProjects) || undefined;
@@ -214,24 +231,26 @@ export const useUrlFilterParams = ({ preset }: { preset?: FilterById }) => {
const router = useRouter();
const [currentPreset, setCurrentPreset] = useState(preset);
const [prevPreset, setPrevPreset] = useState(preset);
- const { queryState, queryFilterState, groupBy, hideCriteria, hideEmptyProjects, view } = useMemo(() => {
- const query = currentPreset ? Object.fromEntries(new URLSearchParams(currentPreset.params)) : router.query;
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- const { groupBy, view, id, ...queries } = query;
-
- const { queryState = undefined, queryFilterState = undefined } = Object.keys(queries).length
- ? parseQueryState({ groupBy, view, ...queries })
- : {};
-
- return {
- queryFilterState,
- queryState,
- groupBy: groupBy as GroupByParam | undefined,
- view: view as PageView | undefined,
- hideCriteria: queryState?.hideCriteria,
- hideEmptyProjects: queryState?.hideEmptyProjects,
- };
- }, [router.query, currentPreset]);
+ const { queryState, queryFilterState, projectsSort, groupBy, hideCriteria, hideEmptyProjects, view } =
+ useMemo(() => {
+ const query = currentPreset ? Object.fromEntries(new URLSearchParams(currentPreset.params)) : router.query;
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ const { groupBy, view, id, ...queries } = query;
+
+ const { queryState = undefined, queryFilterState = undefined } = Object.keys(queries).length
+ ? parseQueryState({ groupBy, view, ...queries })
+ : {};
+
+ return {
+ queryFilterState,
+ queryState,
+ groupBy: groupBy as GroupByParam | undefined,
+ view: view as PageView | undefined,
+ hideCriteria: queryState?.hideCriteria,
+ projectsSort: queryState?.projectsSort,
+ hideEmptyProjects: queryState?.hideEmptyProjects,
+ };
+ }, [router.query, currentPreset]);
const queryString = router.asPath.split('?')[1];
@@ -312,6 +331,7 @@ export const useUrlFilterParams = ({ preset }: { preset?: FilterById }) => {
watching: false,
query: '',
sort: [],
+ projectsSort: [],
groupBy: undefined,
view: undefined,
hideCriteria: undefined,
@@ -368,6 +388,7 @@ export const useUrlFilterParams = ({ preset }: { preset?: FilterById }) => {
setStarredFilter: pushStateProvider.key('starred'),
setWatchingFilter: pushStateProvider.key('watching'),
setSortFilter: pushStateProvider.key('sort'),
+ setProjectsSortFilter: pushStateProvider.key('projectsSort'),
setFulltextFilter: pushStateProvider.key('query'),
setLimitFilter: pushStateProvider.key('limit'),
setGroupBy: pushStateProvider.key('groupBy'),
@@ -381,6 +402,7 @@ export const useUrlFilterParams = ({ preset }: { preset?: FilterById }) => {
return {
queryState,
+ projectsSort,
queryFilterState,
queryString,
currentPreset,
diff --git a/src/schema/common.ts b/src/schema/common.ts
index fe08ecb94..029a890aa 100644
--- a/src/schema/common.ts
+++ b/src/schema/common.ts
@@ -11,17 +11,39 @@ export const StateTypeEnum = z.nativeEnum(StateType);
export type ToggleSubscription = z.infer;
const sortDirectionValue = z.enum(['asc', 'desc']);
-const sortPropEnum = z.enum(['title', 'state', 'priority', 'project', 'activity', 'owner', 'updatedAt', 'createdAt']);
+const sortGoalsPropEnum = z.enum([
+ 'title',
+ 'state',
+ 'priority',
+ 'project',
+ 'activity',
+ 'owner',
+ 'updatedAt',
+ 'createdAt',
+]);
-export const sortablePropertiesArraySchema = z
+const sortProjectsPropEnum = z.enum(['title', 'owner', 'updatedAt', 'createdAt', 'stargizers', 'watchers', 'goals']);
+
+export const sortableGoalsPropertiesArraySchema = z
.array(
z.object({
- key: sortPropEnum,
+ key: sortGoalsPropEnum,
dir: sortDirectionValue,
}),
)
.optional();
+export const sortableProjectsPropertiesArraySchema = z
+ .array(
+ z.object({
+ key: sortProjectsPropEnum,
+ dir: sortDirectionValue,
+ }),
+ )
+ .optional();
+
+export type SortableProjectsPropertiesArray = z.infer;
+
export const queryWithFiltersSchema = z.object({
priority: z.array(z.string()).optional(),
state: z.array(z.string()).optional(),
@@ -33,7 +55,7 @@ export const queryWithFiltersSchema = z.object({
participant: z.array(z.string()).optional(),
project: z.array(z.string()).optional(),
partnershipProject: z.array(z.string()).optional(),
- sort: sortablePropertiesArraySchema,
+ sort: sortableGoalsPropertiesArraySchema,
query: z.string().optional(),
starred: z.boolean().optional(),
watching: z.boolean().optional(),
diff --git a/trpc/queries/projectV2.ts b/trpc/queries/projectV2.ts
index 93a1f8337..e347a281b 100644
--- a/trpc/queries/projectV2.ts
+++ b/trpc/queries/projectV2.ts
@@ -1,9 +1,10 @@
-import { sql } from 'kysely';
+import { AnyColumnWithTable, Expression, OrderByExpression, sql } from 'kysely';
import { jsonBuildObject } from 'kysely/helpers/postgres';
+import { OrderByDirection } from 'kysely/dist/cjs/parser/order-by-parser';
import { db } from '../connection/kysely';
-import { Role } from '../../generated/kysely/types';
-import { QueryWithFilters } from '../../src/schema/common';
+import { DB, Role } from '../../generated/kysely/types';
+import { QueryWithFilters, SortableProjectsPropertiesArray } from '../../src/schema/common';
import { decodeUrlDateRange, getDateString } from '../../src/utils/dateTime';
import { mapSortParamsToTableColumns } from './goalV2';
@@ -223,9 +224,53 @@ export const getUserProjectsQuery = ({
.orderBy('Project.updatedAt desc');
};
+const mapProjectsSortParamsToTableColumns = (
+ sort: SortableProjectsPropertiesArray = [],
+): Array> => {
+ if (!sort.length) {
+ return ['Project.updatedAt desc'];
+ }
+
+ const mapToTableColumn: Record<
+ NonNullable[number]['key'],
+ AnyColumnWithTable | Record>
+ > = {
+ title: 'Project.title',
+ updatedAt: 'Project.updatedAt',
+ createdAt: 'Project.createdAt',
+ stargizers: {
+ asc: sql`(select count("A") from "_projectStargizers" where "B" = "Project".id) asc`,
+ desc: sql`(select count("A") from "_projectStargizers" where "B" = "Project".id) desc`,
+ },
+ watchers: {
+ asc: sql`(select count("A") from "_projectStargizers" where "B" = "Project".id) asc`,
+ desc: sql`(select count("A") from "_projectStargizers" where "B" = "Project".id) desc`,
+ },
+ owner: {
+ asc: sql`(select name from "User" where "User"."activityId" = "Project"."activityId") asc`,
+ desc: sql`(select name from "User" where "User"."activityId" = "Project"."activityId") desc`,
+ },
+ goals: {
+ asc: sql`(select count(*) from "Goal" where "Goal"."projectId" = "Project".id) asc`,
+ desc: sql`(select count(*) from "Goal" where "Goal"."projectId" = "Project".id) desc`,
+ },
+ };
+
+ return sort.map>(({ key, dir }) => {
+ const rule = mapToTableColumn[key];
+
+ if (typeof rule === 'string') {
+ return `${rule} ${dir}`;
+ }
+
+ return rule[dir];
+ });
+};
+
interface GetUserDashboardProjectsParams extends GetUserProjectsQueryParams {
in?: Array<{ id: string }>;
goalsQuery?: QueryWithFilters;
+ projectsSort?: SortableProjectsPropertiesArray;
limit?: number;
offset?: number;
}
@@ -452,7 +497,7 @@ export const getUserDashboardProjects = (params: GetUserDashboardProjectsParams)
]),
)
.groupBy('Project.id')
- .orderBy('Project.updatedAt desc')
+ .orderBy(mapProjectsSortParamsToTableColumns(params.projectsSort))
.$if(!!params.goalsQuery?.hideEmptyProjects, (qb) => qb.having(({ fn }) => fn.count('goal.id'), '>', 0))
.limit(params.limit || 5)
.offset(params.offset || 0);
@@ -530,6 +575,7 @@ interface GetAllProjectsQueryParams {
limit: number;
cursor: number;
ids?: string[];
+ projectsSort?: SortableProjectsPropertiesArray;
}
export const getAllProjectsQuery = ({
@@ -539,6 +585,7 @@ export const getAllProjectsQuery = ({
ids = [],
limit,
cursor,
+ projectsSort,
}: GetAllProjectsQueryParams) => {
return db
.selectFrom(({ selectFrom }) =>
@@ -590,7 +637,7 @@ export const getAllProjectsQuery = ({
)
.limit(limit)
.offset(cursor)
- .orderBy(['Project.updatedAt desc', 'Project.id asc'])
+ .orderBy(mapProjectsSortParamsToTableColumns(projectsSort))
.groupBy(['Project.id'])
.as('projects'),
)
diff --git a/trpc/router/projectV2.ts b/trpc/router/projectV2.ts
index e4f365c03..a0ec4a0fd 100644
--- a/trpc/router/projectV2.ts
+++ b/trpc/router/projectV2.ts
@@ -15,7 +15,7 @@ import {
getAllProjectsQuery,
getChildrenProjectQuery,
} from '../queries/projectV2';
-import { queryWithFiltersSchema } from '../../src/schema/common';
+import { queryWithFiltersSchema, sortableProjectsPropertiesArraySchema } from '../../src/schema/common';
import {
Project,
User,
@@ -169,10 +169,11 @@ export const project = router({
limit: z.number().optional(),
goalsQuery: queryWithFiltersSchema.optional(),
cursor: z.number().optional(),
+ projectsSort: sortableProjectsPropertiesArraySchema.optional(),
}),
)
.query(async ({ ctx, input }) => {
- const { limit = 5, cursor: offset = 0, goalsQuery } = input;
+ const { limit = 5, cursor: offset = 0, goalsQuery, projectsSort } = input;
const {
session: { user },
} = ctx;
@@ -180,6 +181,7 @@ export const project = router({
const dashboardProjects = await getUserDashboardProjects({
...user,
goalsQuery,
+ projectsSort,
limit: limit + 1,
offset,
})
@@ -229,12 +231,13 @@ export const project = router({
z.object({
limit: z.number().optional(),
goalsQuery: queryWithFiltersSchema.optional(),
+ projectsSort: sortableProjectsPropertiesArraySchema.optional(),
firstLevel: z.boolean(),
cursor: z.number().optional(),
}),
)
.query(async ({ input, ctx }) => {
- const { limit = 20, cursor = 0, goalsQuery, firstLevel: _ = true } = input;
+ const { limit = 20, cursor = 0, goalsQuery, projectsSort, firstLevel: _ = true } = input;
const projects = await getAllProjectsQuery({
...ctx.session.user,
@@ -242,6 +245,7 @@ export const project = router({
limit: limit + 1,
cursor,
ids: goalsQuery?.project,
+ projectsSort,
})
.$castTo & Pick>()
.execute();