Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
18 changes: 9 additions & 9 deletions shared/src/api/generated/graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1741,7 +1741,7 @@ export type StatsOperation =
| 'PERCENTAGE_NOT_FILLED'
| 'SUM';

export type ActivityFragmentFragment = { activityId: string, activityType: string, activityData: string, referenceType: string, referenceId: string, entityId: string | null, body: string, createdAt: unknown, updatedAt: unknown, author: { name: string, deleted: boolean, active: boolean, attrib: { fullName: string | null } } | null, files: Array<{ id: string, name: string | null, size: string, mime: string | null }>, origin: { id: string, name: string, label: string | null, type: string } | null, reactions: Array<{ fullName: string | null, userName: string, reaction: string, timestamp: unknown }>, version: { thumbnailHash: string, attrib: { comment: string | null } } | null };
export type ActivityFragmentFragment = { activityId: string, activityType: string, activityData: string, referenceType: string, referenceId: string, entityId: string | null, body: string, createdAt: unknown, updatedAt: unknown, author: { name: string, deleted: boolean, active: boolean, attrib: { fullName: string | null } } | null, files: Array<{ id: string, name: string | null, size: string, mime: string | null }>, origin: { id: string, name: string, label: string | null, type: string } | null, reactions: Array<{ fullName: string | null, userName: string, reaction: string, timestamp: unknown }>, version: { thumbnailHash: string, status: string, attrib: { comment: string | null } } | null };

export type GetActivitiesByIdQueryVariables = Exact<{
projectName: string;
Expand All @@ -1750,7 +1750,7 @@ export type GetActivitiesByIdQueryVariables = Exact<{
}>;


export type GetActivitiesByIdQuery = { project: { name: string, activities: { pageInfo: { hasPreviousPage: boolean, hasNextPage: boolean, startCursor: string | null, endCursor: string | null }, edges: Array<{ cursor: string | null, node: { activityId: string, activityType: string, activityData: string, referenceType: string, referenceId: string, entityId: string | null, body: string, createdAt: unknown, updatedAt: unknown, author: { name: string, deleted: boolean, active: boolean, attrib: { fullName: string | null } } | null, files: Array<{ id: string, name: string | null, size: string, mime: string | null }>, origin: { id: string, name: string, label: string | null, type: string } | null, reactions: Array<{ fullName: string | null, userName: string, reaction: string, timestamp: unknown }>, version: { thumbnailHash: string, attrib: { comment: string | null } } | null } }> } } };
export type GetActivitiesByIdQuery = { project: { name: string, activities: { pageInfo: { hasPreviousPage: boolean, hasNextPage: boolean, startCursor: string | null, endCursor: string | null }, edges: Array<{ cursor: string | null, node: { activityId: string, activityType: string, activityData: string, referenceType: string, referenceId: string, entityId: string | null, body: string, createdAt: unknown, updatedAt: unknown, author: { name: string, deleted: boolean, active: boolean, attrib: { fullName: string | null } } | null, files: Array<{ id: string, name: string | null, size: string, mime: string | null }>, origin: { id: string, name: string, label: string | null, type: string } | null, reactions: Array<{ fullName: string | null, userName: string, reaction: string, timestamp: unknown }>, version: { thumbnailHash: string, status: string, attrib: { comment: string | null } } | null } }> } } };

export type GetActivityUsersQueryVariables = Exact<{
projects?: Array<string> | string | null | undefined;
Expand All @@ -1773,7 +1773,7 @@ export type GetActivitiesQueryVariables = Exact<{
}>;


export type GetActivitiesQuery = { project: { name: string, activities: { pageInfo: { hasPreviousPage: boolean, hasNextPage: boolean, startCursor: string | null, endCursor: string | null }, edges: Array<{ cursor: string | null, node: { activityId: string, activityType: string, activityData: string, referenceType: string, referenceId: string, entityId: string | null, body: string, createdAt: unknown, updatedAt: unknown, author: { name: string, deleted: boolean, active: boolean, attrib: { fullName: string | null } } | null, files: Array<{ id: string, name: string | null, size: string, mime: string | null }>, origin: { id: string, name: string, label: string | null, type: string } | null, reactions: Array<{ fullName: string | null, userName: string, reaction: string, timestamp: unknown }>, version: { thumbnailHash: string, attrib: { comment: string | null } } | null } }> } } };
export type GetActivitiesQuery = { project: { name: string, activities: { pageInfo: { hasPreviousPage: boolean, hasNextPage: boolean, startCursor: string | null, endCursor: string | null }, edges: Array<{ cursor: string | null, node: { activityId: string, activityType: string, activityData: string, referenceType: string, referenceId: string, entityId: string | null, body: string, createdAt: unknown, updatedAt: unknown, author: { name: string, deleted: boolean, active: boolean, attrib: { fullName: string | null } } | null, files: Array<{ id: string, name: string | null, size: string, mime: string | null }>, origin: { id: string, name: string, label: string | null, type: string } | null, reactions: Array<{ fullName: string | null, userName: string, reaction: string, timestamp: unknown }>, version: { thumbnailHash: string, status: string, attrib: { comment: string | null } } | null } }> } } };

export type GetEntitiesChecklistsQueryVariables = Exact<{
projectName: string;
Expand Down Expand Up @@ -1957,7 +1957,7 @@ export type GetTasksByParentQueryVariables = Exact<{
}>;


export type GetTasksByParentQuery = { project: { name: string, tasks: { edges: Array<{ node: { id: string, folderId: string, label: string | null, name: string, ownAttrib: Array<string>, status: string, tags: Array<string>, taskType: string, updatedAt: unknown, createdAt: unknown, thumbnailHash: string, active: boolean, assignees: Array<string>, allAttrib: string, hasReviewables: boolean, parents: Array<string>, subtasks: Array<{ id: string, name: string, label: string, assignees: Array<string>, description: string | null, startDate: unknown, endDate: unknown, isDone: boolean }>, latestComments?: Array<{ activityId: string, body: string, author: string | null, createdAt: string }> | null, folder: { folderType: string, taskCount: number } } }>, pageInfo: { hasNextPage: boolean, endCursor: string | null } } } };
export type GetTasksByParentQuery = { project: { name: string, tasks: { edges: Array<{ node: { id: string, folderId: string, label: string | null, name: string, ownAttrib: Array<string>, status: string, tags: Array<string>, taskType: string, updatedAt: unknown, createdAt: unknown, thumbnailHash: string, active: boolean, assignees: Array<string>, allAttrib: string, hasReviewables: boolean, parents: Array<string>, subtasks: Array<{ id: string, name: string, label: string, assignees: Array<string>, description: string | null, startDate: unknown, endDate: unknown, isDone: boolean }>, latestComments?: Array<{ activityId: string, body: string, author: string | null, createdAt: string }> | null, folder: { folderType: string } } }>, pageInfo: { hasNextPage: boolean, endCursor: string | null } } } };

export type GetTasksListQueryVariables = Exact<{
projectName: string;
Expand All @@ -1976,11 +1976,11 @@ export type GetTasksListQueryVariables = Exact<{
}>;


export type GetTasksListQuery = { project: { name: string, tasks: { pageInfo: { startCursor: string | null, endCursor: string | null, hasNextPage: boolean, hasPreviousPage: boolean }, edges: Array<{ cursor: string | null, node: { id: string, folderId: string, label: string | null, name: string, ownAttrib: Array<string>, status: string, tags: Array<string>, taskType: string, updatedAt: unknown, createdAt: unknown, thumbnailHash: string, active: boolean, assignees: Array<string>, allAttrib: string, hasReviewables: boolean, parents: Array<string>, subtasks: Array<{ id: string, name: string, label: string, assignees: Array<string>, description: string | null, startDate: unknown, endDate: unknown, isDone: boolean }>, latestComments?: Array<{ activityId: string, body: string, author: string | null, createdAt: string }> | null, folder: { folderType: string, taskCount: number } } }> } } };
export type GetTasksListQuery = { project: { name: string, tasks: { pageInfo: { startCursor: string | null, endCursor: string | null, hasNextPage: boolean, hasPreviousPage: boolean }, edges: Array<{ cursor: string | null, node: { id: string, folderId: string, label: string | null, name: string, ownAttrib: Array<string>, status: string, tags: Array<string>, taskType: string, updatedAt: unknown, createdAt: unknown, thumbnailHash: string, active: boolean, assignees: Array<string>, allAttrib: string, hasReviewables: boolean, parents: Array<string>, subtasks: Array<{ id: string, name: string, label: string, assignees: Array<string>, description: string | null, startDate: unknown, endDate: unknown, isDone: boolean }>, latestComments?: Array<{ activityId: string, body: string, author: string | null, createdAt: string }> | null, folder: { folderType: string } } }> } } };

export type SubTaskFragmentFragment = { id: string, name: string, label: string, assignees: Array<string>, description: string | null, startDate: unknown, endDate: unknown, isDone: boolean };

export type TaskPropsFragmentFragment = { id: string, folderId: string, label: string | null, name: string, ownAttrib: Array<string>, status: string, tags: Array<string>, taskType: string, updatedAt: unknown, createdAt: unknown, thumbnailHash: string, active: boolean, assignees: Array<string>, allAttrib: string, hasReviewables: boolean, parents: Array<string>, subtasks: Array<{ id: string, name: string, label: string, assignees: Array<string>, description: string | null, startDate: unknown, endDate: unknown, isDone: boolean }>, latestComments?: Array<{ activityId: string, body: string, author: string | null, createdAt: string }> | null, folder: { folderType: string, taskCount: number } };
export type TaskPropsFragmentFragment = { id: string, folderId: string, label: string | null, name: string, ownAttrib: Array<string>, status: string, tags: Array<string>, taskType: string, updatedAt: unknown, createdAt: unknown, thumbnailHash: string, active: boolean, assignees: Array<string>, allAttrib: string, hasReviewables: boolean, parents: Array<string>, subtasks: Array<{ id: string, name: string, label: string, assignees: Array<string>, description: string | null, startDate: unknown, endDate: unknown, isDone: boolean }>, latestComments?: Array<{ activityId: string, body: string, author: string | null, createdAt: string }> | null, folder: { folderType: string } };

export type GetFolderProductsQueryVariables = Exact<{
projectName: string;
Expand Down Expand Up @@ -2279,6 +2279,7 @@ export const ActivityFragmentFragmentDoc = new TypedDocumentString(`
}
version {
thumbnailHash
status
attrib {
comment
}
Expand Down Expand Up @@ -2501,7 +2502,6 @@ export const TaskPropsFragmentFragmentDoc = new TypedDocumentString(`
}
folder {
folderType
taskCount
}
}
fragment SubTaskFragment on SubTaskNode {
Expand Down Expand Up @@ -2783,6 +2783,7 @@ export const GetActivitiesByIdDocument = new TypedDocumentString(`
}
version {
thumbnailHash
status
attrib {
comment
}
Expand Down Expand Up @@ -2870,6 +2871,7 @@ export const GetActivitiesDocument = new TypedDocumentString(`
}
version {
thumbnailHash
status
attrib {
comment
}
Expand Down Expand Up @@ -3525,7 +3527,6 @@ fragment TaskPropsFragment on TaskNode {
}
folder {
folderType
taskCount
}
}`);
export const GetTasksListDocument = new TypedDocumentString(`
Expand Down Expand Up @@ -3598,7 +3599,6 @@ fragment TaskPropsFragment on TaskNode {
}
folder {
folderType
taskCount
}
}`);
export const GetFolderProductsDocument = new TypedDocumentString(`
Expand Down
58 changes: 9 additions & 49 deletions shared/src/api/queries/activities/getActivities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
GetActivityUsersQuery,
GetEntitiesChecklistsQuery,
} from '@shared/api/generated'
import { taskProvideTags } from './util/activitiesHelpers'
import { provideSharedActivityTags, taskProvideTags } from './util/activitiesHelpers'
import {
ActivitiesResult,
countChecklists,
Expand Down Expand Up @@ -43,28 +43,7 @@ const enhanceActivitiesApi = gqlApi.enhanceEndpoints<TagTypes, UpdatedDefinition
GetActivities: {
transformResponse: (res: GetActivitiesQuery) =>
transformActivityData(res.project.activities.edges, res.project.activities.pageInfo),
// @ts-expect-error - filter is not an query arg
providesTags: (result, _e, { entityIds, activityTypes = [], filter }) =>
result
? [
...result.activities.map((a) => ({ type: 'activity', id: a.activityId })),
{ type: 'activity', id: 'LIST' },
...(Array.isArray(entityIds) ? entityIds : [entityIds]).map((id) => ({
type: 'entityActivities',
id: id,
})),
{ type: 'entityActivities', id: 'LIST' },
...(Array.isArray(activityTypes) ? activityTypes : [activityTypes])?.map((type) => ({
type: 'entityActivities',
id: type as string,
})),
// filter is used when a comment is made, to refetch the activities of other filters
...(Array.isArray(entityIds) ? entityIds : [entityIds]).map((id) => ({
type: 'entityActivities',
id: id + '-' + filterKey(filter),
})),
]
: [{ type: 'activity', id: 'LIST' }],
providesTags: provideSharedActivityTags,
},
GetActivitiesById: {
transformResponse: (res: GetActivitiesByIdQuery) =>
Expand Down Expand Up @@ -94,13 +73,18 @@ const enhanceActivitiesApi = gqlApi.enhanceEndpoints<TagTypes, UpdatedDefinition
},
})

export type GetActivitiesInfiniteQueryArgs = Omit<
GetActivitiesQueryVariables,
'last' | 'first' | 'cursor'
> & { filter?: any }

const ACTIVITIES_INFINITE_QUERY_COUNT = 30

const getActivitiesGQLApi = enhanceActivitiesApi.injectEndpoints({
endpoints: (build) => ({
getActivitiesInfinite: build.infiniteQuery<
ActivitiesResult,
Omit<GetActivitiesQueryVariables, 'last' | 'first' | 'cursor'> & { filter?: any },
GetActivitiesInfiniteQueryArgs,
{ cursor: string; first?: number; last?: number }
>({
infiniteQueryOptions: {
Expand Down Expand Up @@ -168,31 +152,7 @@ const getActivitiesGQLApi = enhanceActivitiesApi.injectEndpoints({
gqlApi: enhanceActivitiesApi,
})
},
providesTags: (result, _e, { entityIds, activityTypes, filter }) =>
result
? [
...result.pages
.flatMap((page) => page.activities)
.map((a) => ({ type: 'activity', id: a.activityId })),
{ type: 'activity', id: 'LIST' },
...(Array.isArray(entityIds) ? entityIds : [entityIds]).filter(Boolean).map((id) => ({
type: 'entityActivities',
id: id as string,
})),
{ type: 'entityActivities', id: 'LIST' },
...(Array.isArray(activityTypes) ? activityTypes : [activityTypes])
?.filter(Boolean)
.map((type) => ({
type: 'entityActivities',
id: type as string,
})),
// filter is used when a comment is made, to refetch the activities of other filters
...(Array.isArray(entityIds) ? entityIds : [entityIds]).filter(Boolean).map((id) => ({
type: 'entityActivities',
id: `${id}-${filterKey(filter)}`,
})),
]
: [{ type: 'activity', id: 'LIST' }],
providesTags: provideSharedActivityTags,
}),
// get data for a reference tooltip based on type,id and projectName
getEntityTooltip: build.query({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ fragment ActivityFragment on ActivityNode {
}
version {
thumbnailHash
status
attrib {
comment
}
Expand Down
58 changes: 58 additions & 0 deletions shared/src/api/queries/activities/util/activitiesHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,64 @@ export const filterKey = (filter: any): string => {
}
}

/**
* Shared helper to generate activity tags for both standard and infinite queries.
*/
export const provideSharedActivityTags = (
result: { activities?: any[]; pages?: Array<{ activities: any[] }> } | undefined,
_error: unknown,
// Widened type signatures to allow string[] | string | null | undefined
arg: {
entityIds?: string | string[] | null
activityTypes?: string | string[] | null
filter?: any
},
) => {
if (!result) {
return [{ type: 'activity' as const, id: 'LIST' }]
}

const { entityIds, activityTypes, filter } = arg

// Helper now safely skips null/undefined values
const normalizeIds = (ids: unknown): string[] =>
(Array.isArray(ids) ? ids : [ids]).filter(Boolean) as string[]

const cleanEntityIds = normalizeIds(entityIds)
const cleanActivityTypes = normalizeIds(activityTypes)

const activities = result.pages
? result.pages.flatMap((page) => page.activities)
: result.activities || []

return [
// Individual Activity Tags
...activities.map((a) => ({ type: 'activity' as const, id: a.activityId })),
{ type: 'activity' as const, id: 'LIST' },

// Base Entity Activity Tags
...cleanEntityIds.map((id) => ({ type: 'entityActivities' as const, id })),
{ type: 'entityActivities' as const, id: 'LIST' },

// Activity Type Tags
...cleanActivityTypes.map((type) => ({ type: 'entityActivities' as const, id: type })),

// Filtered Entity Activity Tags
...cleanEntityIds.map((id) => ({
type: 'entityActivities' as const,
id: `${id}-${filterKey(filter)}`,
})),

// Published Version Tags
...activities
.filter((a) => a.activityType === 'version.publish')
.map((a) => ({
type: 'entityActivities' as const,
id: `version.publish-${a.origin.id}`,
})),
]
}

export const filterActivityTypes: Record<string, string[]> = {
activity: [
'comment',
Expand Down
26 changes: 24 additions & 2 deletions shared/src/api/queries/activities/util/activityRealtimeHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,8 +275,30 @@ export const handleActivityRealtimeUpdates = async (
} else {
console.warn('[Activity RT] Cannot add activity: no pages or activities array')
}
} else if (!existingActivityFound) {
} else {
}

// If this is a status change, update any version.publish activities in the cache
if (
newActivity.activityType === 'status.change' &&
newActivity.origin?.type === 'version'
) {
const versionId = newActivity.origin.id
const newStatus = newActivity.activityData?.newValue
if (newStatus) {
draft.pages.forEach((page) => {
page.activities?.forEach((activity) => {
if (
activity.activityType === 'version.publish' &&
activity.origin?.id === versionId
) {
if (!activity.version) {
activity.version = {} as any
}
activity.version!.status = newStatus
}
})
})
}
}
})
} catch (error) {
Expand Down
13 changes: 7 additions & 6 deletions shared/src/api/queries/entities/updateEntity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -369,12 +369,6 @@ const updateEntity = api.injectEndpoints({
throw 'Failed to update some tasks'
}

const activityTags = []

if (activityTags.length) {
dispatch(api.util.invalidateTags(activityTags))
}

return { data: operations }
} catch (error) {
console.error(error)
Expand All @@ -391,6 +385,13 @@ const updateEntity = api.injectEndpoints({
if (entityType === 'version') {
tags.push({ type: 'version', id: 'LIST' }, { type: 'product', id: 'LIST' })
operations.forEach((o) => tags.push({ type: 'version', id: o.id }))
if (operations.some((o) => !!o.data.status)) {
console.log('invalidate version.publish activities')
// invalidate feeds with that version in it (published versions activity)
operations.forEach((o) =>
tags.push({ type: 'entityActivities', id: `version.publish-${o.id}` }),
)
}
}

return tags
Expand Down
Loading