diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 106e2e8a480..be0ab283b23 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "8.23.7" + ".": "8.23.8" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b3295fab4f..22b448f0890 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ This project adheres to [Semantic Versioning](http://semver.org/). This CHANGELOG follows conventions [outlined here](http://keepachangelog.com/). +## [8.23.8](https://github.com/ParabolInc/parabol/compare/v8.23.7...v8.23.8) (2025-02-04) + + +### Fixed + +* Allow navigation in meetings with invalid facilitator stage ([#10791](https://github.com/ParabolInc/parabol/issues/10791)) ([968c4fd](https://github.com/ParabolInc/parabol/commit/968c4fd35eacecd71b4492810e55dd4ead68ec08)) + ## [8.23.7](https://github.com/ParabolInc/parabol/compare/v8.23.6...v8.23.7) (2025-02-04) diff --git a/package.json b/package.json index 8e3f7bc3877..9ecf73b6c1b 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": "8.23.7", + "version": "8.23.8", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" diff --git a/packages/chronos/package.json b/packages/chronos/package.json index 1209dfafb8f..3be84e9e240 100644 --- a/packages/chronos/package.json +++ b/packages/chronos/package.json @@ -1,6 +1,6 @@ { "name": "chronos", - "version": "8.23.7", + "version": "8.23.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": "8.23.7" + "parabol-server": "8.23.8" } } diff --git a/packages/client/mutations/RemoveMultipleOrgUsersMutation.ts b/packages/client/mutations/RemoveMultipleOrgUsersMutation.ts new file mode 100644 index 00000000000..74b6145956e --- /dev/null +++ b/packages/client/mutations/RemoveMultipleOrgUsersMutation.ts @@ -0,0 +1,287 @@ +import graphql from 'babel-plugin-relay/macro' +import {commitLocalUpdate, commitMutation} from 'react-relay' +import {RecordProxy} from 'relay-runtime' +import {RemoveMultipleOrgUsersMutation as TRemoveMultipleOrgUsersMutation} from '~/__generated__/RemoveMultipleOrgUsersMutation.graphql' +import {RemoveMultipleOrgUsersMutation_organization$data} from '~/__generated__/RemoveMultipleOrgUsersMutation_organization.graphql' +import {RemoveMultipleOrgUsersMutation_notification$data} from '../__generated__/RemoveMultipleOrgUsersMutation_notification.graphql' +import {RemoveMultipleOrgUsersMutation_task$data} from '../__generated__/RemoveMultipleOrgUsersMutation_task.graphql' +import {RemoveMultipleOrgUsersMutation_team$data} from '../__generated__/RemoveMultipleOrgUsersMutation_team.graphql' +import { + HistoryLocalHandler, + OnNextHandler, + OnNextHistoryContext, + SharedUpdater, + StandardMutation +} from '../types/relayMutations' +import findStageById from '../utils/meetings/findStageById' +import onExOrgRoute from '../utils/onExOrgRoute' +import onMeetingRoute from '../utils/onMeetingRoute' +import onTeamRoute from '../utils/onTeamRoute' +import {setLocalStageAndPhase} from '../utils/relay/updateLocalStage' +import handleAddNotifications from './handlers/handleAddNotifications' +import handleRemoveOrgMembers from './handlers/handleRemoveOrgMembers' +import handleRemoveOrganization from './handlers/handleRemoveOrganization' +import handleRemoveTasks from './handlers/handleRemoveTasks' +import handleRemoveTeamMembers from './handlers/handleRemoveTeamMembers' +import handleRemoveTeams from './handlers/handleRemoveTeams' +import handleUpsertTasks from './handlers/handleUpsertTasks' + +graphql` + fragment RemoveMultipleOrgUsersMutation_organization on RemoveMultipleOrgUsersSuccess { + organization { + id + } + users { + id + } + removedOrgMembers { + id + } + } +` + +graphql` + fragment RemoveMultipleOrgUsersMutation_notification on RemoveMultipleOrgUsersSuccess { + organization { + id + name + } + kickOutNotifications { + id + type + team { + id + name + activeMeetings { + id + } + } + ...KickedOut_notification + } + } +` + +graphql` + fragment RemoveMultipleOrgUsersMutation_team on RemoveMultipleOrgUsersSuccess { + teamMembers { + id + } + users { + id + } + teams { + ...RemoveTeamMemberMutation_teamTeam @relay(mask: false) + activeMeetings { + id + } + } + } +` + +graphql` + fragment RemoveMultipleOrgUsersMutation_task on RemoveMultipleOrgUsersSuccess { + updatedTasks { + ...CompleteTaskFrag @relay(mask: false) + } + users { + id + } + } +` + +const mutation = graphql` + mutation RemoveMultipleOrgUsersMutation($userIds: [ID!]!, $orgId: ID!) { + removeMultipleOrgUsers(userIds: $userIds, orgId: $orgId) { + ... on ErrorPayload { + error { + message + } + } + ... on RemoveMultipleOrgUsersSuccess { + ...RemoveMultipleOrgUsersMutation_organization @relay(mask: false) + ...RemoveMultipleOrgUsersMutation_team @relay(mask: false) + ...RemoveMultipleOrgUsersMutation_task @relay(mask: false) + ...RemoveMultipleOrgUsersMutation_notification @relay(mask: false) + } + } + } +` + +export const removeMultipleOrgUsersOrganizationUpdater: SharedUpdater< + RemoveMultipleOrgUsersMutation_organization$data +> = (payload, {atmosphere, store}) => { + const {viewerId} = atmosphere + const users = payload.getLinkedRecords('users') + const removedOrgMembers = payload.getLinkedRecords('removedOrgMembers') + const orgId = payload.getLinkedRecord('organization').getValue('id') + + if (users.some((user) => user.getValue('id') === viewerId)) { + handleRemoveOrganization(orgId, store) + } else { + removedOrgMembers.forEach((member) => { + handleRemoveOrgMembers(orgId, member.getValue('id'), store) + }) + } +} + +export const removeMultipleOrgUsersNotificationUpdater: SharedUpdater< + RemoveMultipleOrgUsersMutation_notification$data +> = (payload, {store}) => { + const kickOutNotifications = payload.getLinkedRecords('kickOutNotifications') + handleAddNotifications(kickOutNotifications, store) +} + +export const removeMultipleOrgUsersTeamUpdater: SharedUpdater< + RemoveMultipleOrgUsersMutation_team$data +> = (payload, {atmosphere, store}) => { + const users = payload.getLinkedRecords('users') + const {viewerId} = atmosphere + + if (users.some((user) => user.getValue('id') === viewerId)) { + const teams = payload.getLinkedRecords('teams') + const teamIds = teams.map((team) => team.getValue('id')) + handleRemoveTeams(teamIds, store) + } else { + const teamMembers = payload.getLinkedRecords('teamMembers') + const teamMemberIds = teamMembers?.map((teamMember) => teamMember.getValue('id')) + handleRemoveTeamMembers(teamMemberIds, store) + } +} + +export const removeMultipleOrgUsersTaskUpdater: SharedUpdater< + RemoveMultipleOrgUsersMutation_task$data +> = (payload, {atmosphere, store}) => { + const users = payload.getLinkedRecords('users') + const tasks = payload.getLinkedRecords('updatedTasks') + if (!tasks) return + + if (users.some((user) => user.getValue('id') === atmosphere.viewerId)) { + const taskIds = tasks.map((task) => task.getValue('id')) + handleRemoveTasks(taskIds, store) + } else { + handleUpsertTasks(tasks, store) + } +} + +export const removeMultipleOrgUsersTeamOnNext: OnNextHandler< + RemoveMultipleOrgUsersMutation_team$data +> = (payload, context) => { + const {atmosphere} = context + const {teams} = payload + if (!teams) return + teams.forEach((team) => { + const {activeMeetings} = team + activeMeetings.forEach((newMeeting) => { + const {id: meetingId, facilitatorStageId, phases} = newMeeting + commitLocalUpdate(atmosphere, (store) => { + const meetingProxy = store.get(meetingId) + if (!meetingProxy) return + const localStage = meetingProxy.getLinkedRecord('localStage') + if (!localStage) return + const viewerStageId = localStage.getValue('id') as string + const stageRes = findStageById(phases, viewerStageId) + if (!stageRes) { + setLocalStageAndPhase(store, meetingId, facilitatorStageId) + } + }) + }) + }) +} + +export const removeMultipleOrgUsersOrganizationOnNext: OnNextHandler< + RemoveMultipleOrgUsersMutation_organization$data, + OnNextHistoryContext +> = (payload, context) => { + const { + atmosphere: {viewerId}, + history + } = context + const {pathname} = history.location + const {users, organization} = payload + const orgId = organization?.id ?? '' + if (users.some((user) => user.id === viewerId) && onExOrgRoute(pathname, orgId)) { + history.push('/meetings') + } +} + +export const removeMultipleOrgUsersNotificationOnNext: OnNextHandler< + RemoveMultipleOrgUsersMutation_notification$data, + OnNextHistoryContext +> = (payload, {atmosphere, history}) => { + if (!payload) return + const {organization, kickOutNotifications} = payload + if (!organization || !kickOutNotifications) return + const {name: orgName, id: orgId} = organization + const teams = kickOutNotifications.map((notification) => notification && notification.team) + atmosphere.eventEmitter.emit('addSnackbar', { + key: `removedFromOrg:${orgId}`, + autoDismiss: 10, + message: `You have been removed from ${orgName} and all its teams` + }) + + for (let ii = 0; ii < teams.length; ii++) { + const team = teams[ii] + if (!team) continue + const {activeMeetings, id: teamId} = team + const meetingIds = activeMeetings.map(({id}) => id) + if ( + onTeamRoute(window.location.pathname, teamId) || + onMeetingRoute(window.location.pathname, meetingIds) + ) { + history.push('/meetings') + return + } + } +} + +const RemoveMultipleOrgUsersMutation: StandardMutation< + TRemoveMultipleOrgUsersMutation, + HistoryLocalHandler +> = (atmosphere, variables, {history, onError, onCompleted}) => { + return commitMutation(atmosphere, { + mutation, + variables, + updater: (store) => { + const payload = store.getRootField('removeMultipleOrgUsers') + if (!payload) return + if (payload.getValue('error')) return + const success = payload.getLinkedRecord('RemoveMultipleOrgUsersSuccess') + if (!success) return + + const organizationSuccess = + success as RecordProxy + const teamSuccess = success as RecordProxy + const taskSuccess = success as RecordProxy + const notificationSuccess = + success as RecordProxy + + removeMultipleOrgUsersOrganizationUpdater(organizationSuccess, {atmosphere, store}) + removeMultipleOrgUsersTeamUpdater(teamSuccess, {atmosphere, store}) + removeMultipleOrgUsersTaskUpdater(taskSuccess, {atmosphere, store}) + removeMultipleOrgUsersNotificationUpdater(notificationSuccess, {atmosphere, store}) + }, + onCompleted: (res, errors) => { + if (onCompleted) { + onCompleted(res, errors) + } + const payload = res.removeMultipleOrgUsers + if (!payload || !('success' in payload)) return + const {success} = payload + if (!success) return + + const organizationSuccess = success as RemoveMultipleOrgUsersMutation_organization$data + const teamSuccess = success as RemoveMultipleOrgUsersMutation_team$data + const notificationSuccess = success as RemoveMultipleOrgUsersMutation_notification$data + + removeMultipleOrgUsersOrganizationOnNext(organizationSuccess, { + history, + atmosphere + }) + removeMultipleOrgUsersTeamOnNext(teamSuccess, {atmosphere}) + removeMultipleOrgUsersNotificationOnNext(notificationSuccess, {atmosphere, history}) + }, + onError + }) +} + +export default RemoveMultipleOrgUsersMutation diff --git a/packages/client/package.json b/packages/client/package.json index bd7eaf01bdd..cd48606e76b 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": "8.23.7", + "version": "8.23.8", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" diff --git a/packages/embedder/package.json b/packages/embedder/package.json index 3f0c04ade8b..3655878c85c 100644 --- a/packages/embedder/package.json +++ b/packages/embedder/package.json @@ -1,6 +1,6 @@ { "name": "parabol-embedder", - "version": "8.23.7", + "version": "8.23.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 352cefd9d2f..d44199415bf 100644 --- a/packages/gql-executor/package.json +++ b/packages/gql-executor/package.json @@ -1,6 +1,6 @@ { "name": "gql-executor", - "version": "8.23.7", + "version": "8.23.8", "description": "A Stateless GraphQL Executor", "author": "Matt Krick ", "homepage": "https://github.com/ParabolInc/parabol/tree/master/packages/gqlExecutor#readme", @@ -25,8 +25,8 @@ }, "dependencies": { "dd-trace": "^5.0.0", - "parabol-client": "8.23.7", - "parabol-server": "8.23.7", + "parabol-client": "8.23.8", + "parabol-server": "8.23.8", "undici": "^5.26.2" } } diff --git a/packages/integration-tests/package.json b/packages/integration-tests/package.json index 5262b7102d5..b079957dabd 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": "8.23.7", + "version": "8.23.8", "description": "", "main": "index.js", "scripts": { diff --git a/packages/mattermost-plugin/package.json b/packages/mattermost-plugin/package.json index 5d4cd9ceb9c..75d0befc40a 100644 --- a/packages/mattermost-plugin/package.json +++ b/packages/mattermost-plugin/package.json @@ -1,6 +1,6 @@ { "name": "parabol-mattermost-plugin", - "version": "8.23.7", + "version": "8.23.8", "description": "A service that computes embedding vectors from Parabol objects", "author": "Georg Bremer ", "homepage": "https://github.com/ParabolInc/parabol/tree/master/packages/mattermost-plugin#readme", @@ -48,7 +48,7 @@ "ts-node-dev": "^1.0.0-pre.44" }, "dependencies": { - "parabol-client": "8.23.7", + "parabol-client": "8.23.8", "@mattermost/compass-icons": "0.1.47", "@reduxjs/toolkit": "1.9.7", "@tiptap/core": "^2.9.1", diff --git a/packages/server/package.json b/packages/server/package.json index b0b0a8df847..853f3a04b23 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": "8.23.7", + "version": "8.23.8", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" @@ -126,7 +126,7 @@ "oauth-1.0a": "^2.2.6", "openai": "^4.53.0", "oy-vey": "^0.12.1", - "parabol-client": "8.23.7", + "parabol-client": "8.23.8", "pg": "^8.5.1", "react": "^17.0.2", "react-dom": "^17.0.2",