Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add project select to the contributors page gf-504 #516

Merged
merged 25 commits into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
d2721c0
feat: add select project component gf-504
GvoFor Sep 24, 2024
885afb7
feat: place loader inside table gf-504
GvoFor Sep 24, 2024
c89a88a
fix: display only contributors of selected project gf-504
GvoFor Sep 24, 2024
c28407c
fix: findAllByProjectId so it returns all contributor's projects and …
GvoFor Sep 24, 2024
b982717
fix: findAll methods so all of them orders results in descending orde…
GvoFor Sep 24, 2024
658988e
refactor: rid of code duplication and fix pagination when project sel…
GvoFor Sep 25, 2024
2ec5044
fix: remove unneccessary changes and fix import gf-504
GvoFor Sep 25, 2024
8954a80
Merge branch 'main' into 504-feat-add-project-select-to-contributors-…
GvoFor Sep 25, 2024
7818fa2
fix: do not render untracked contributor cards gf-504
GvoFor Sep 25, 2024
c118158
Merge branch 'main' into 504-feat-add-project-select-to-contributors-…
GvoFor Sep 25, 2024
9c2ac01
fix: update contributor.controller findAll swagger comment gf-504
GvoFor Sep 25, 2024
8a4e774
Merge branch 'main' into 504-feat-add-project-select-to-contributors-…
GvoFor Sep 25, 2024
4471e96
feat: link Select with URL gf-504
GvoFor Sep 25, 2024
85861f8
fix: include contributorName into queryToSend gf-504
GvoFor Sep 26, 2024
81316c3
refactor: fix A10 QC gf-504
GvoFor Sep 26, 2024
4c6b161
Merge branch 'main' into 504-feat-add-project-select-to-contributors-…
GvoFor Sep 26, 2024
59ab1bb
fix: order of contributor cards gf-504
GvoFor Sep 26, 2024
bd621ac
refactor: use enum values gf-504
GvoFor Sep 26, 2024
c38accb
refactor: rename RequestDto to queryParameters gf-504
GvoFor Sep 26, 2024
33bf93e
refactor: rename ContributorOrderBy to ContributorOrderByKey gf-504
GvoFor Sep 26, 2024
3e14e24
refactor: move contributor orderBy validation to schema gf-504
GvoFor Sep 26, 2024
daf3498
refactor: make projectId be a number in ActivityLogQueryParameters ty…
GvoFor Sep 26, 2024
99169d2
Merge branch 'main' into 504-feat-add-project-select-to-contributors-…
GvoFor Sep 26, 2024
49b34ee
Merge branch 'main' into 504-feat-add-project-select-to-contributors-…
GvoFor Sep 27, 2024
94dc279
refactor: remove TODO comment gf-504
GvoFor Sep 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -216,12 +216,12 @@ class ActivityLogController extends BaseController {

return {
payload: await this.activityLogService.findAll({
contributorName,
endDate,
hasRootPermission,
projectId,
startDate,
userProjectIds,
...(contributorName ? { contributorName } : {}),
...(projectId ? { projectId: Number(projectId) } : {}),
}),
status: HTTPCode.OK,
};
Expand Down
17 changes: 5 additions & 12 deletions apps/backend/src/modules/activity-logs/activity-log.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,18 +188,11 @@ class ActivityLogService implements Service {
item.toObject(),
);

const allContributors = await (projectId
? this.contributorService.findAllByProjectId({
contributorName: contributorName ?? "",
hasHidden: false,
permittedProjectIds,
projectId: Number(projectId),
})
: this.contributorService.findAllWithoutPagination({
contributorName: contributorName ?? "",
hasHidden: false,
permittedProjectIds,
}));
const allContributors = await this.contributorService.findAll({
contributorName,
permittedProjectIds,
projectId,
});

const dateRange = getDateRange(formattedStartDate, formattedEndDate);

Expand Down
59 changes: 39 additions & 20 deletions apps/backend/src/modules/contributors/contributor.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,17 @@ import {
} from "~/libs/modules/controller/controller.js";
import { HTTPCode } from "~/libs/modules/http/http.js";
import { type Logger } from "~/libs/modules/logger/logger.js";
import { type PaginationQueryParameters } from "~/libs/types/types.js";

import { type ContributorService } from "./contributor.service.js";
import { ContributorsApiPath } from "./libs/enums/enums.js";
import {
type ContributorGetAllQueryParameters,
type ContributorMergeRequestDto,
type ContributorPatchRequestDto,
type ContributorSplitRequestDto,
} from "./libs/types/types.js";
import {
contributorGetAllValidationSchema,
contributorMergeValidationSchema,
contributorPatchValidationSchema,
contributorSplitValidationSchema,
Expand Down Expand Up @@ -71,7 +72,7 @@ class ContributorController extends BaseController {
handler: (options) =>
this.findAll(
options as APIHandlerOptions<{
query: { projectId?: string } & PaginationQueryParameters;
query: ContributorGetAllQueryParameters;
}>,
),
method: "GET",
Expand All @@ -94,6 +95,9 @@ class ContributorController extends BaseController {
),
),
],
validation: {
query: contributorGetAllValidationSchema,
},
});

this.addRoute({
Expand Down Expand Up @@ -156,18 +160,39 @@ class ContributorController extends BaseController {
* schema:
* type: integer
* description: The page number to retrieve
* required: false
* - in: query
* name: pageSize
* schema:
* type: integer
* description: Number of items per page
* required: false
* - name: projectId
* in: query
* description: Id of a project contributor should belong to
* required: false
* schema:
* type: number
* minimum: 1
* - name: hasHidden
* in: query
* description: Determines whether include all contributors or tracked only
* required: false
* schema:
* type: boolean
* - name: contributorName
* in: query
* description: Contributor name search query
* required: false
* schema:
* type: string
* - name: orderBy
* in: query
* description: Field by which to sort contributors
* required: false
* schema:
* type: string
* enum: [created_at, last_activity_date]
* responses:
* 200:
* description: Successful operation
Expand All @@ -183,29 +208,23 @@ class ContributorController extends BaseController {
*/
private async findAll(
options: APIHandlerOptions<{
query: { projectId?: string } & PaginationQueryParameters;
query: ContributorGetAllQueryParameters;
}>,
): Promise<APIHandlerResponse> {
const { page, pageSize, projectId } = options.query;

if (projectId) {
return {
payload: await this.contributorService.findAllByProjectId({
projectId: Number(projectId),
}),
status: HTTPCode.OK,
};
}
const { contributorName, hasHidden, orderBy, page, pageSize, projectId } =
options.query;

if (!page || !pageSize) {
return {
payload: await this.contributorService.findAllWithoutPagination({}),
status: HTTPCode.OK,
};
}
const query = {
...(contributorName ? { contributorName } : {}),
...(hasHidden ? { hasHidden: (hasHidden as unknown) === "true" } : {}),
...(orderBy ? { orderBy } : {}),
...(page ? { page: Number(page) } : {}),
...(pageSize ? { pageSize: Number(pageSize) } : {}),
...(projectId ? { projectId: Number(projectId) } : {}),
};

return {
payload: await this.contributorService.findAll(options.query),
payload: await this.contributorService.findAll(query),
status: HTTPCode.OK,
};
}
Expand Down
129 changes: 29 additions & 100 deletions apps/backend/src/modules/contributors/contributor.repository.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { raw } from "objection";

import { EMPTY_LENGTH } from "~/libs/constants/constants.js";
import { EMPTY_LENGTH, PAGE_INDEX_OFFSET } from "~/libs/constants/constants.js";
import { SortType } from "~/libs/enums/enums.js";
import {
type PaginationResponseDto,
Expand All @@ -10,6 +10,7 @@ import { type GitEmailModel } from "~/modules/git-emails/git-emails.js";

import { ContributorEntity } from "./contributor.entity.js";
import { type ContributorModel } from "./contributor.model.js";
import { ContributorOrderByKey } from "./libs/enums/enums.js";
import {
type ContributorGetAllQueryParameters,
type ContributorMergeRequestDto,
Expand Down Expand Up @@ -58,57 +59,17 @@ class ContributorRepository implements Repository {

public async findAll({
contributorName,
hasHidden = true,
hasHidden = false,
orderBy = ContributorOrderByKey.CREATED_AT,
page,
pageSize,
}: { hasHidden?: boolean } & ContributorGetAllQueryParameters): Promise<
PaginationResponseDto<ContributorEntity>
> {
const query = this.contributorModel
.query()
.orderBy("createdAt", SortType.DESCENDING)
.page(page, pageSize)
.select("contributors.*")
.select(
raw(
"COALESCE(ARRAY_AGG(DISTINCT jsonb_build_object('id', projects.id, 'name', projects.name)) FILTER (WHERE projects.id IS NOT NULL), '{}') AS projects",
),
)
.leftJoin("git_emails", "contributors.id", "git_emails.contributor_id")
.leftJoin("activity_logs", "git_emails.id", "activity_logs.git_email_id")
.leftJoin("projects", "activity_logs.project_id", "projects.id")
.groupBy("contributors.id")
.withGraphFetched("gitEmails");

if (!hasHidden) {
query.whereNull("contributors.hiddenAt");
}

if (contributorName) {
query.whereILike("contributors.name", `%${contributorName}%`);
}

const { results, total } = await query.execute();

return {
items: results.map((contributor) =>
ContributorEntity.initialize(contributor),
),
totalItems: total,
};
}

public async findAllByProjectId({
contributorName,
hasHidden = true,
permittedProjectIds,
permittedProjectIds = [],
projectId,
}: {
contributorName?: string;
hasHidden?: boolean;
permittedProjectIds?: number[] | undefined;
projectId: number;
}): Promise<{ items: ContributorEntity[] }> {
} & ContributorGetAllQueryParameters): Promise<
PaginationResponseDto<ContributorEntity>
> {
const query = this.contributorModel
.query()
.select("contributors.*")
Expand All @@ -125,18 +86,8 @@ class ContributorRepository implements Repository {
.leftJoin("git_emails", "contributors.id", "git_emails.contributor_id")
.leftJoin("activity_logs", "git_emails.id", "activity_logs.git_email_id")
.leftJoin("projects", "activity_logs.project_id", "projects.id")
.where("projects.id", projectId)
.whereNull("contributors.hiddenAt")
.groupBy("contributors.id")
.withGraphFetched("gitEmails")
.orderBy("last_activity_date", SortType.DESCENDING);

const hasPermissionedProjects =
permittedProjectIds && permittedProjectIds.length !== EMPTY_LENGTH;

if (hasPermissionedProjects) {
query.whereIn("projects.id", permittedProjectIds);
}
.withGraphFetched("gitEmails");

if (!hasHidden) {
query.whereNull("contributors.hiddenAt");
Expand All @@ -146,59 +97,37 @@ class ContributorRepository implements Repository {
query.whereILike("contributors.name", `%${contributorName}%`);
}

const contributorsWithProjectsAndEmails = await query.execute();

return {
items: contributorsWithProjectsAndEmails.map((contributor) => {
return ContributorEntity.initialize(contributor);
}),
};
}

public async findAllWithoutPagination({
contributorName,
hasHidden = true,
permittedProjectIds,
}: {
contributorName?: string;
hasHidden?: boolean;
permittedProjectIds: number[] | undefined;
}): Promise<{ items: ContributorEntity[] }> {
const query = this.contributorModel
.query()
.select("contributors.*")
.select(
raw(
"COALESCE(ARRAY_AGG(DISTINCT jsonb_build_object('id', projects.id, 'name', projects.name)) FILTER (WHERE projects.id IS NOT NULL), '{}') AS projects",
),
)
.leftJoin("git_emails", "contributors.id", "git_emails.contributor_id")
.leftJoin("activity_logs", "git_emails.id", "activity_logs.git_email_id")
.leftJoin("projects", "activity_logs.project_id", "projects.id")
.groupBy("contributors.id")
.withGraphFetched("gitEmails");

if (!hasHidden) {
query.whereNull("contributors.hiddenAt");
}

if (contributorName) {
query.whereILike("contributors.name", `%${contributorName}%`);
if (projectId) {
query.havingRaw("?? = ANY(ARRAY_AGG(projects.id))", projectId);
}

const hasPermissionedProjects =
permittedProjectIds && permittedProjectIds.length !== EMPTY_LENGTH;
const hasPermissionedProjects = permittedProjectIds.length !== EMPTY_LENGTH;

if (hasPermissionedProjects) {
query.whereIn("projects.id", permittedProjectIds);
}

const results = await query.execute();
query.orderBy(orderBy, SortType.DESCENDING);

let contributors, totalItems;

if (page && pageSize) {
const { results, total } = await query.page(
page - PAGE_INDEX_OFFSET,
pageSize,
);
contributors = results;
totalItems = total;
} else {
contributors = await query;
totalItems = contributors.length;
}

return {
items: results.map((contributor) => {
items: contributors.map((contributor) => {
return ContributorEntity.initialize(contributor);
}),
totalItems,
};
}

Expand Down
Loading