diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 10a5df74e1a..6bdf9ff88da 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "7.37.6" + ".": "7.37.8" } diff --git a/CHANGELOG.md b/CHANGELOG.md index d9dd7494367..79484a06a85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,20 @@ This project adheres to [Semantic Versioning](http://semver.org/). This CHANGELOG follows conventions [outlined here](http://keepachangelog.com/). +## [7.37.8](https://github.com/ParabolInc/parabol/compare/v7.37.7...v7.37.8) (2024-06-27) + + +### Fixed + +* timeline ordering ([#9898](https://github.com/ParabolInc/parabol/issues/9898)) ([9f5f38c](https://github.com/ParabolInc/parabol/commit/9f5f38c250fbb1d0af4aaed8526c19f0fc6fd111)) + +## [7.37.7](https://github.com/ParabolInc/parabol/compare/v7.37.6...v7.37.7) (2024-06-27) + + +### Changed + +* **rethinkdb:** TimelineEvent: Phase 3 ([#9876](https://github.com/ParabolInc/parabol/issues/9876)) ([77b56ad](https://github.com/ParabolInc/parabol/commit/77b56ad296bd3ff69f2a8f3440a34a7b5f34c0cf)) + ## [7.37.6](https://github.com/ParabolInc/parabol/compare/v7.37.5...v7.37.6) (2024-06-27) diff --git a/package.json b/package.json index e247eb15498..8d0e796e8f0 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.37.6", + "version": "7.37.8", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" diff --git a/packages/chronos/package.json b/packages/chronos/package.json index 86c0006f54d..a88696f59fd 100644 --- a/packages/chronos/package.json +++ b/packages/chronos/package.json @@ -1,6 +1,6 @@ { "name": "chronos", - "version": "7.37.6", + "version": "7.37.8", "description": "A cron job scheduler", "author": "Matt Krick ", "homepage": "https://github.com/ParabolInc/parabol/tree/master/packages/chronos#readme", @@ -25,6 +25,6 @@ }, "dependencies": { "cron": "^2.3.1", - "parabol-server": "7.37.6" + "parabol-server": "7.37.8" } } diff --git a/packages/client/package.json b/packages/client/package.json index c218236cb4d..64822b443f4 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.37.6", + "version": "7.37.8", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" diff --git a/packages/embedder/package.json b/packages/embedder/package.json index 30aa64b6536..ccb4172b3cd 100644 --- a/packages/embedder/package.json +++ b/packages/embedder/package.json @@ -1,6 +1,6 @@ { "name": "parabol-embedder", - "version": "7.37.6", + "version": "7.37.8", "description": "A service that computes embedding vectors from Parabol objects", "author": "Jordan Husney ", "homepage": "https://github.com/ParabolInc/parabol/tree/master/packages/embedder#readme", diff --git a/packages/gql-executor/package.json b/packages/gql-executor/package.json index 39fb6a3563d..1aaf90bc810 100644 --- a/packages/gql-executor/package.json +++ b/packages/gql-executor/package.json @@ -1,6 +1,6 @@ { "name": "gql-executor", - "version": "7.37.6", + "version": "7.37.8", "description": "A Stateless GraphQL Executor", "author": "Matt Krick ", "homepage": "https://github.com/ParabolInc/parabol/tree/master/packages/gqlExecutor#readme", @@ -27,8 +27,8 @@ }, "dependencies": { "dd-trace": "^4.2.0", - "parabol-client": "7.37.6", - "parabol-server": "7.37.6", + "parabol-client": "7.37.8", + "parabol-server": "7.37.8", "undici": "^5.26.2" } } diff --git a/packages/integration-tests/package.json b/packages/integration-tests/package.json index 71460560979..16caa3e64cd 100644 --- a/packages/integration-tests/package.json +++ b/packages/integration-tests/package.json @@ -2,7 +2,7 @@ "name": "integration-tests", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.37.6", + "version": "7.37.8", "description": "", "main": "index.js", "scripts": { diff --git a/packages/server/database/rethinkDriver.ts b/packages/server/database/rethinkDriver.ts index d66cde79213..d88791af467 100644 --- a/packages/server/database/rethinkDriver.ts +++ b/packages/server/database/rethinkDriver.ts @@ -36,7 +36,6 @@ import SuggestedActionTryTheDemo from './types/SuggestedActionTryTheDemo' import Task from './types/Task' import TemplateDimension from './types/TemplateDimension' import TemplateScale from './types/TemplateScale' -import TimelineEvent from './types/TimelineEvent' export type RethinkSchema = { AgendaItem: { @@ -187,10 +186,6 @@ export type RethinkSchema = { type: TemplateScale index: 'teamId' } - TimelineEvent: { - type: TimelineEvent - index: 'userIdCreatedAt' | 'meetingId' - } } export type DBType = { diff --git a/packages/server/dataloader/foreignKeyLoaderMakers.ts b/packages/server/dataloader/foreignKeyLoaderMakers.ts index dc57123c89a..9bfccba0e94 100644 --- a/packages/server/dataloader/foreignKeyLoaderMakers.ts +++ b/packages/server/dataloader/foreignKeyLoaderMakers.ts @@ -60,3 +60,17 @@ export const retroReflectionsByGroupId = foreignKeyLoaderMaker( .execute() } ) + +export const timelineEventsByMeetingId = foreignKeyLoaderMaker( + 'timelineEvents', + 'meetingId', + async (meetingIds) => { + const pg = getKysely() + return pg + .selectFrom('TimelineEvent') + .selectAll() + .where('meetingId', 'in', meetingIds) + .where('isActive', '=', true) + .execute() + } +) diff --git a/packages/server/dataloader/primaryKeyLoaderMakers.ts b/packages/server/dataloader/primaryKeyLoaderMakers.ts index a3f096efbda..dcb6eb8ac0a 100644 --- a/packages/server/dataloader/primaryKeyLoaderMakers.ts +++ b/packages/server/dataloader/primaryKeyLoaderMakers.ts @@ -53,3 +53,7 @@ export const selectRetroReflections = () => export const retroReflections = primaryKeyLoaderMaker((ids: readonly string[]) => { return selectRetroReflections().where('id', 'in', ids).execute() }) + +export const timelineEvents = primaryKeyLoaderMaker((ids: readonly string[]) => { + return getKysely().selectFrom('TimelineEvent').selectAll().where('id', 'in', ids).execute() +}) diff --git a/packages/server/dataloader/rethinkForeignKeyLoaderMakers.ts b/packages/server/dataloader/rethinkForeignKeyLoaderMakers.ts index 24a4abe50d0..461c58dd606 100644 --- a/packages/server/dataloader/rethinkForeignKeyLoaderMakers.ts +++ b/packages/server/dataloader/rethinkForeignKeyLoaderMakers.ts @@ -1,5 +1,3 @@ -import TimelineEventCheckinComplete from 'parabol-server/database/types/TimelineEventCheckinComplete' -import TimelineEventRetroComplete from 'parabol-server/database/types/TimelineEventRetroComplete' import getRethink from '../database/rethinkDriver' import {RDatum} from '../database/stricterR' import RethinkForeignKeyLoaderMaker from './RethinkForeignKeyLoaderMaker' @@ -182,18 +180,6 @@ export const templateDimensionsByTemplateId = new RethinkForeignKeyLoaderMaker( ) } ) -export const timelineEventsByMeetingId = new RethinkForeignKeyLoaderMaker( - 'timelineEvents', - 'meetingId', - async (meetingIds) => { - const r = await getRethink() - return r - .table('TimelineEvent') - .getAll(r.args(meetingIds), {index: 'meetingId'}) - .filter({isActive: true}) - .run() as Promise - } -) export const slackAuthByUserId = new RethinkForeignKeyLoaderMaker( 'slackAuths', diff --git a/packages/server/dataloader/rethinkPrimaryKeyLoaderMakers.ts b/packages/server/dataloader/rethinkPrimaryKeyLoaderMakers.ts index 1a4efd5417a..d5dbd237079 100644 --- a/packages/server/dataloader/rethinkPrimaryKeyLoaderMakers.ts +++ b/packages/server/dataloader/rethinkPrimaryKeyLoaderMakers.ts @@ -23,4 +23,3 @@ export const tasks = new RethinkPrimaryKeyLoaderMaker('Task') export const teamMembers = new RethinkPrimaryKeyLoaderMaker('TeamMember') export const teamInvitations = new RethinkPrimaryKeyLoaderMaker('TeamInvitation') export const templateDimensions = new RethinkPrimaryKeyLoaderMaker('TemplateDimension') -export const timelineEvents = new RethinkPrimaryKeyLoaderMaker('TimelineEvent') diff --git a/packages/server/graphql/mutations/archiveTimelineEvent.ts b/packages/server/graphql/mutations/archiveTimelineEvent.ts index f116011eece..bbada88ed8b 100644 --- a/packages/server/graphql/mutations/archiveTimelineEvent.ts +++ b/packages/server/graphql/mutations/archiveTimelineEvent.ts @@ -2,7 +2,6 @@ import {GraphQLID, GraphQLNonNull} from 'graphql' import {SubscriptionChannel} from 'parabol-client/types/constEnums' import TimelineEventCheckinComplete from 'parabol-server/database/types/TimelineEventCheckinComplete' import TimelineEventRetroComplete from 'parabol-server/database/types/TimelineEventRetroComplete' -import getRethink from '../../database/rethinkDriver' import {TimelineEventEnum} from '../../database/types/TimelineEvent' import getKysely from '../../postgres/getKysely' import {getUserId, isTeamMember} from '../../utils/authorization' @@ -25,7 +24,6 @@ const archiveTimelineEvent = { {timelineEventId}: {timelineEventId: string}, {authToken, dataLoader, socketId: mutatorId}: GQLContext ) => { - const r = await getRethink() const operationId = dataLoader.share() const subOptions = {mutatorId, operationId} const viewerId = getUserId(authToken) @@ -59,14 +57,11 @@ const archiveTimelineEvent = { .load(meetingId) const eventIds = meetingTimelineEvents.map(({id}) => id) const pg = getKysely() - await Promise.all([ - pg - .updateTable('TimelineEvent') - .set({isActive: false}) - .where('id', 'in', eventIds) - .execute(), - r.table('TimelineEvent').getAll(r.args(eventIds)).update({isActive: false}).run() - ]) + await pg + .updateTable('TimelineEvent') + .set({isActive: false}) + .where('id', 'in', eventIds) + .execute() meetingTimelineEvents.map((event) => { const {id: timelineEventId, userId} = event publish( diff --git a/packages/server/graphql/mutations/endCheckIn.ts b/packages/server/graphql/mutations/endCheckIn.ts index 71a0b38313e..c97e2f7cd03 100644 --- a/packages/server/graphql/mutations/endCheckIn.ts +++ b/packages/server/graphql/mutations/endCheckIn.ts @@ -246,10 +246,7 @@ export default { ) const timelineEventId = events[0]!.id const pg = getKysely() - await Promise.all([ - pg.insertInto('TimelineEvent').values(events).execute(), - r.table('TimelineEvent').insert(events).run() - ]) + await pg.insertInto('TimelineEvent').values(events).execute() if (team.isOnboardTeam) { const teamLeadUserId = await r .table('TeamMember') diff --git a/packages/server/graphql/mutations/endSprintPoker.ts b/packages/server/graphql/mutations/endSprintPoker.ts index 250fc524130..267aa3eb4cf 100644 --- a/packages/server/graphql/mutations/endSprintPoker.ts +++ b/packages/server/graphql/mutations/endSprintPoker.ts @@ -129,10 +129,7 @@ export default { }) ) const pg = getKysely() - await Promise.all([ - pg.insertInto('TimelineEvent').values(events).execute(), - r.table('TimelineEvent').insert(events).run() - ]) + await pg.insertInto('TimelineEvent').values(events).execute() const data = { meetingId, diff --git a/packages/server/graphql/mutations/helpers/bootstrapNewUser.ts b/packages/server/graphql/mutations/helpers/bootstrapNewUser.ts index b2100882ef4..9fb461504f6 100644 --- a/packages/server/graphql/mutations/helpers/bootstrapNewUser.ts +++ b/packages/server/graphql/mutations/helpers/bootstrapNewUser.ts @@ -71,8 +71,7 @@ const bootstrapNewUser = async ( ) .insertInto('TimelineEvent') .values(joinEvent) - .execute(), - r.table('TimelineEvent').insert(joinEvent).run() + .execute() ]) // Identify the user so user properties are set before any events are sent diff --git a/packages/server/graphql/mutations/helpers/createTeamAndLeader.ts b/packages/server/graphql/mutations/helpers/createTeamAndLeader.ts index c46773ded75..f76a2540d27 100644 --- a/packages/server/graphql/mutations/helpers/createTeamAndLeader.ts +++ b/packages/server/graphql/mutations/helpers/createTeamAndLeader.ts @@ -47,7 +47,6 @@ export default async function createTeamAndLeader(user: IUser, newTeam: ValidNew r.table('MeetingSettings').insert(meetingSettings).run(), // denormalize common fields to team member insertNewTeamMember(user, teamId), - r.table('TimelineEvent').insert(timelineEvent).run(), addTeamIdToTMS(userId, teamId) ]) } diff --git a/packages/server/graphql/mutations/helpers/safeEndRetrospective.ts b/packages/server/graphql/mutations/helpers/safeEndRetrospective.ts index 0467adf031b..a76ba6fe7c8 100644 --- a/packages/server/graphql/mutations/helpers/safeEndRetrospective.ts +++ b/packages/server/graphql/mutations/helpers/safeEndRetrospective.ts @@ -165,10 +165,7 @@ const safeEndRetrospective = async ({ ) const timelineEventId = events[0]!.id const pg = getKysely() - await Promise.all([ - pg.insertInto('TimelineEvent').values(events).execute(), - r.table('TimelineEvent').insert(events).run() - ]) + await pg.insertInto('TimelineEvent').values(events).execute() if (team.isOnboardTeam) { const teamLeadUserId = await r diff --git a/packages/server/graphql/mutations/helpers/safeEndTeamPrompt.ts b/packages/server/graphql/mutations/helpers/safeEndTeamPrompt.ts index 57cc38f293f..e88ed41daf1 100644 --- a/packages/server/graphql/mutations/helpers/safeEndTeamPrompt.ts +++ b/packages/server/graphql/mutations/helpers/safeEndTeamPrompt.ts @@ -104,10 +104,7 @@ const safeEndTeamPrompt = async ({ ) const timelineEventId = events[0]!.id const pg = getKysely() - await Promise.all([ - pg.insertInto('TimelineEvent').values(events).execute(), - r.table('TimelineEvent').insert(events).run() - ]) + await pg.insertInto('TimelineEvent').values(events).execute() summarizeTeamPrompt(meeting, context) analytics.teamPromptEnd(completedTeamPrompt, meetingMembers, responses, dataLoader) checkTeamsLimit(team.orgId, dataLoader) diff --git a/packages/server/graphql/private/mutations/backupOrganization.ts b/packages/server/graphql/private/mutations/backupOrganization.ts index 4a2687025e0..cfc321db1ad 100644 --- a/packages/server/graphql/private/mutations/backupOrganization.ts +++ b/packages/server/graphql/private/mutations/backupOrganization.ts @@ -256,17 +256,7 @@ const backupOrganization: MutationResolvers['backupOrganization'] = async (_sour r.or(row('teamId').default(null).eq(null), r(teamIds).contains(row('teamId'))) ) .coerceTo('array') - .do((items: RValue) => r.db(DESTINATION).table('SuggestedAction').insert(items)), - timelineEvent: ( - r - .table('TimelineEvent') - .filter((row: RDatum) => r(userIds).contains(row('userId'))) as any - ) - .filter((row: RValue) => - r.branch(row('teamId'), r(teamIds).contains(row('teamId')), true) - ) - .coerceTo('array') - .do((items: RValue) => r.db(DESTINATION).table('TimelineEvent').insert(items)) + .do((items: RValue) => r.db(DESTINATION).table('SuggestedAction').insert(items)) }) }), meetingIds: r diff --git a/packages/server/graphql/private/mutations/hardDeleteUser.ts b/packages/server/graphql/private/mutations/hardDeleteUser.ts index da6a190260c..22d3084aba1 100644 --- a/packages/server/graphql/private/mutations/hardDeleteUser.ts +++ b/packages/server/graphql/private/mutations/hardDeleteUser.ts @@ -117,12 +117,6 @@ const hardDeleteUser: MutationResolvers['hardDeleteUser'] = async ( .getAll(r.args(teamIds), {index: 'teamId'}) .filter((row: RValue) => row('createdBy').eq(userIdToDelete)) .delete(), - timelineEvent: r - .table('TimelineEvent') - .between([userIdToDelete, r.minval], [userIdToDelete, r.maxval], { - index: 'userIdCreatedAt' - }) - .delete(), agendaItem: r .table('AgendaItem') .getAll(r.args(teamIds), {index: 'teamId'}) diff --git a/packages/server/graphql/types/User.ts b/packages/server/graphql/types/User.ts index f26db140ccb..78b6b2380dd 100644 --- a/packages/server/graphql/types/User.ts +++ b/packages/server/graphql/types/User.ts @@ -15,13 +15,11 @@ import { MAX_RESULT_GROUP_SIZE } from '../../../client/utils/constants' import groupReflections from '../../../client/utils/smartGroup/groupReflections' -import getRethink from '../../database/rethinkDriver' -import {RDatum} from '../../database/stricterR' import MeetingMemberType from '../../database/types/MeetingMember' import OrganizationType from '../../database/types/Organization' import OrganizationUserType from '../../database/types/OrganizationUser' import SuggestedActionType from '../../database/types/SuggestedAction' -import TimelineEvent from '../../database/types/TimelineEvent' +import getKysely from '../../postgres/getKysely' import {getUserId, isSuperUser, isTeamMember} from '../../utils/authorization' import getMonthlyStreak from '../../utils/getMonthlyStreak' import getRedis from '../../utils/getRedis' @@ -217,7 +215,6 @@ const User: GraphQLObjectType = new GraphQLObjectType { - const r = await getRethink() const viewerId = getUserId(authToken) // VALIDATE @@ -244,21 +241,21 @@ const User: GraphQLObjectType = new GraphQLObjectType) => - eventTypes ? r.expr(eventTypes).contains(t('type')) : true - ) - .filter((t: RDatum) => r.expr(validTeamIds).contains(t('teamId'))) - .orderBy(r.desc('createdAt')) + const dbAfter = after ? new Date(after) : new Date('3000-01-01') + const minVal = new Date(0) + + const pg = getKysely() + const events = await pg + .selectFrom('TimelineEvent') + .selectAll() + .where('userId', '=', viewerId) + .where((eb) => eb.between('createdAt', minVal, dbAfter)) + .where('isActive', '=', true) + .where('teamId', 'in', validTeamIds) + .$if(!!eventTypes, (db) => db.where('type', 'in', eventTypes)) + .orderBy('createdAt', 'desc') .limit(first + 1) - .coerceTo('array') - .run() + .execute() const edges = events.slice(0, first).map((node) => ({ cursor: node.createdAt, node diff --git a/packages/server/package.json b/packages/server/package.json index 314625b2803..1ec29f34195 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.37.6", + "version": "7.37.8", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" @@ -123,7 +123,7 @@ "oauth-1.0a": "^2.2.6", "openai": "^4.24.1", "oy-vey": "^0.12.1", - "parabol-client": "7.37.6", + "parabol-client": "7.37.8", "pg": "^8.5.1", "react": "^17.0.2", "react-dom": "^17.0.2",