Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
bd70d54
fix: Experiment table sorting not working
shivoomiess Jun 15, 2026
78eaffc
chore: add e2e tests for experiment table sorting
shivoomiess Jun 15, 2026
02a280c
Merge branch 'develop' into SWAP-5630-fix
shivoomiess Jun 15, 2026
5044b1e
chore(types): add type for permissible columns names to sort Experiments
shivoomiess Jun 15, 2026
5e909fb
chore: add e2e for instrument sc and exp safety reviewer
shivoomiess Jun 15, 2026
9dece97
fix: add sort by enum to GQL endpoint
Jun 16, 2026
b94d09a
fix(typo): Reviewer Spelling Fixed
shivoomiess Jun 17, 2026
2045e4b
Merge branch 'SWAP-5630-fix' into SWAP-5630-improve-gql-input-datatype
yoganandaness Jun 18, 2026
b8d1d07
chore: add sort by enum to GQL endpoint (#1585)
shivoomiess Jun 22, 2026
2a4240a
Merge branch 'develop' into SWAP-5630-fix
yoganandaness Jul 6, 2026
ea47443
fix: add review suggestions
shivoomiess Jul 7, 2026
c81eb60
Merge branch 'develop' into SWAP-5630-fix
shivoomiess Jul 7, 2026
2867a94
Merge branch 'develop' into SWAP-5630-fix
yoganandaness Jul 8, 2026
7d59bc4
Merge branch 'develop' of github.com:UserOfficeProject/user-office-co…
shivoomiess Jul 21, 2026
1c36af3
Merge branch 'develop' into SWAP-5630-fix
shivoomiess Jul 21, 2026
6c9fedd
chore: remove debug port from package.json
shivoomiess Jul 21, 2026
375a365
Merge branch 'develop' into SWAP-5630-fix
shivoomiess Jul 21, 2026
f146692
chore: remove .zed
shivoomiess Jul 21, 2026
c15551f
Merge branch 'SWAP-5630-fix' of github.com:UserOfficeProject/user-off…
shivoomiess Jul 21, 2026
f7eba01
Merge branch 'develop' into SWAP-5630-fix
shivoomiess Jul 22, 2026
72a7140
Merge branch 'develop' into SWAP-5630-fix
jekabs-karklins Jul 24, 2026
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
3 changes: 2 additions & 1 deletion apps/backend/src/datasources/ExperimentDataSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
Experiment,
ExperimentHasSample,
ExperimentSafety,
ExperimentTableSortField,
InstrumentScientistDecisionEnum,
ExperimentSafetyReviewerDecisionEnum,
} from '../models/Experiment';
Expand Down Expand Up @@ -87,7 +88,7 @@ export interface ExperimentDataSource {
filter?: ExperimentsFilter,
first?: number,
offset?: number,
sortField?: string,
sortField?: ExperimentTableSortField,
sortDirection?: PaginationSortDirection,
searchText?: string
): Promise<{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
ExperimentSafety,
ExperimentHasSample,
ExperimentStatus,
ExperimentTableSortField,
InstrumentScientistDecisionEnum,
ExperimentSafetyReviewerDecisionEnum,
} from '../../models/Experiment';
Expand Down Expand Up @@ -121,7 +122,7 @@ export class ExperimentDataSourceMock implements ExperimentDataSource {
filter?: ExperimentsFilter,
first?: number,
offset?: number,
sortField?: string,
sortField?: ExperimentTableSortField,
sortDirection?: PaginationSortDirection,
searchText?: string
): Promise<{ totalCount: number; experiments: Experiment[] }> {
Expand Down
26 changes: 21 additions & 5 deletions apps/backend/src/datasources/postgres/ExperimentDataSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
ExperimentHasSample,
ExperimentSafety,
ExperimentSafetyReviewerDecisionEnum,
ExperimentTableSortField,
InstrumentScientistDecisionEnum,
} from '../../models/Experiment';
import { Rejection } from '../../models/Rejection';
Expand Down Expand Up @@ -83,8 +84,23 @@ function generateExperimentId(
return `${proposalNumber}-${sequence ?? 0}`;
}

const fieldMap: { [key: string]: string } = {
experimentId: 'experiment_id',
type SortableExperimentTableColumnName =
| 'experiment_id'
| 'proposal_id'
| 'starts_at'
| 'ends_at';

// Maps a sortable column from the API to its database column.
// Instrument and experiment safety status are intentionally omitted
// (not sortable at the DB layer; create a view later if needed).
const fieldMap: Record<
ExperimentTableSortField,
SortableExperimentTableColumnName
> = {
[ExperimentTableSortField.experimentId]: 'experiment_id',
[ExperimentTableSortField.proposalId]: 'proposal_id',
[ExperimentTableSortField.startsAt]: 'starts_at',
[ExperimentTableSortField.endsAt]: 'ends_at',
};

@injectable()
Expand Down Expand Up @@ -570,7 +586,7 @@ export default class PostgresExperimentDataSource
filter?: ExperimentsFilter,
first?: number,
offset?: number,
sortField?: string,
sortField?: ExperimentTableSortField,
sortDirection?: PaginationSortDirection,
searchText?: string
): Promise<{ totalCount: number; experiments: Experiment[] }> {
Expand Down Expand Up @@ -689,8 +705,8 @@ export default class PostgresExperimentDataSource
if (!fieldMap.hasOwnProperty(sortField)) {
throw new GraphQLError(`Bad sort field given: ${sortField}`);
}
sortField = fieldMap[sortField];
query.orderBy(sortField, sortDirection);
const databaseSortField = fieldMap[sortField];
query.orderBy(databaseSortField, sortDirection);
}

if (first) {
Expand Down
9 changes: 9 additions & 0 deletions apps/backend/src/models/Experiment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ export enum ExperimentStatus {
COMPLETED = 'COMPLETED',
}

// Experiment table columns that support sorting. Lives in the model so it can
// be reused across queries/datasources without importing from the resolver layer.
export enum ExperimentTableSortField {
experimentId = 'experimentId',
proposalId = 'proposalId',
startsAt = 'startsAt',
endsAt = 'endsAt',
}

export class Experiment {
constructor(
public experimentPk: number,
Expand Down
3 changes: 2 additions & 1 deletion apps/backend/src/queries/ExperimentQueries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { UserAuthorization } from '../auth/UserAuthorization';
import { Tokens } from '../config/Tokens';
import { ExperimentDataSource } from '../datasources/ExperimentDataSource';
import { Authorized } from '../decorators';
import { ExperimentTableSortField } from '../models/Experiment';
import { Roles } from '../models/Role';
import { UserWithRole } from '../models/User';
import { ExperimentSampleArgs } from '../resolvers/queries/ExperimentSampleQuery';
Expand Down Expand Up @@ -97,7 +98,7 @@ export default class ExperimentQueries {
filter: ExperimentsFilter = {},
first?: number,
offset?: number,
sortField?: string,
sortField?: ExperimentTableSortField,
sortDirection?: PaginationSortDirection,
searchText?: string
) {
Expand Down
9 changes: 6 additions & 3 deletions apps/backend/src/resolvers/queries/ExperimentsQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ import {
} from 'type-graphql';

import { ResolverContext } from '../../context';
import { ExperimentStatus } from '../../models/Experiment';
import {
ExperimentStatus,
ExperimentTableSortField,
} from '../../models/Experiment';
import { PaginationSortDirection } from '../../utils/pagination';
import { Experiment } from '../types/Experiment';

Expand Down Expand Up @@ -59,8 +62,8 @@ export class ExperimentsArgs {
@Field(() => Int, { nullable: true })
public offset?: number;

@Field({ nullable: true })
public sortField?: string;
@Field(() => ExperimentTableSortField, { nullable: true })
public sortField?: ExperimentTableSortField;

@Field(() => PaginationSortDirection, { nullable: true })
public sortDirection?: PaginationSortDirection;
Expand Down
5 changes: 5 additions & 0 deletions apps/backend/src/resolvers/registerEnums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
import {
ExperimentSafetyReviewerDecisionEnum,
ExperimentStatus,
ExperimentTableSortField,
InstrumentScientistDecisionEnum,
} from '../models/Experiment';
import { FapReviewVisibility } from '../models/Fap';
Expand Down Expand Up @@ -70,6 +71,10 @@ export const registerEnums = () => {
registerEnumType(ExperimentStatus, {
name: 'ExperimentStatus',
});
registerEnumType(ExperimentTableSortField, {
name: 'ExperimentTableSortField',
description: 'Experiment table columns that support sorting',
});
registerEnumType(FeedbackStatus, {
name: 'FeedbackStatus',
});
Expand Down
Loading
Loading