Migrate activities (#2545)

* Start

* Migrate activities to flexible schema
This commit is contained in:
Charles Bochet
2023-11-16 17:10:22 +01:00
committed by GitHub
parent 7da18a13e8
commit dee38bb901
69 changed files with 518 additions and 1479 deletions

View File

@ -8,8 +8,6 @@ import { ComponentWithRouterDecorator } from '~/testing/decorators/ComponentWith
import { graphqlMocks } from '~/testing/graphqlMocks';
import { mockedTasks } from '~/testing/mock-data/activities';
import { ActivityTargetableEntityType } from '../../types/ActivityTargetableEntity';
const meta: Meta<typeof TaskGroups> = {
title: 'Modules/Activity/TaskGroups',
component: TaskGroups,
@ -37,7 +35,7 @@ export const WithTasks: Story = {
args: {
entity: {
id: mockedTasks[0].authorId,
type: ActivityTargetableEntityType.Person,
type: 'Person',
},
},
};

View File

@ -1,13 +1,13 @@
import { ReactElement } from 'react';
import styled from '@emotion/styled';
import { TaskForList } from '@/activities/types/TaskForList';
import { Activity } from '@/activities/types/Activity';
import { TaskRow } from './TaskRow';
type TaskListProps = {
title?: string;
tasks: TaskForList[];
tasks: Omit<Activity, 'assigneeId'>[];
button?: ReactElement | false;
};

View File

@ -3,12 +3,12 @@ import styled from '@emotion/styled';
import { ActivityTargetChips } from '@/activities/components/ActivityTargetChips';
import { useOpenActivityRightDrawer } from '@/activities/hooks/useOpenActivityRightDrawer';
import { Activity } from '@/activities/types/Activity';
import { IconCalendar, IconComment } from '@/ui/display/icon';
import { OverflowingTextWithTooltip } from '@/ui/display/tooltip/OverflowingTextWithTooltip';
import { Checkbox, CheckboxShape } from '@/ui/input/components/Checkbox';
import { beautifyExactDate, hasDatePassed } from '~/utils/date-utils';
import { TaskForList } from '../../types/TaskForList';
import { useCompleteTask } from '../hooks/useCompleteTask';
const StyledContainer = styled.div`
@ -61,7 +61,7 @@ const StyledFieldsContainer = styled.div`
display: flex;
`;
export const TaskRow = ({ task }: { task: TaskForList }) => {
export const TaskRow = ({ task }: { task: Omit<Activity, 'assigneeId'> }) => {
const theme = useTheme();
const openActivityRightDrawer = useOpenActivityRightDrawer();

View File

@ -1,44 +1,26 @@
import { useCallback } from 'react';
import { useApolloClient } from '@apollo/client';
import { getOperationName } from '@apollo/client/utilities';
import { Activity, useUpdateActivityMutation } from '~/generated/graphql';
import { ACTIVITY_UPDATE_FRAGMENT } from '../../graphql/fragments/activityUpdateFragment';
import { GET_ACTIVITIES } from '../../graphql/queries/getActivities';
import { useUpdateOneObjectRecord } from '@/object-record/hooks/useUpdateOneObjectRecord';
import { Activity } from '~/generated/graphql';
type Task = Pick<Activity, 'id' | 'completedAt'>;
export const useCompleteTask = (task: Task) => {
const [updateActivityMutation] = useUpdateActivityMutation();
const client = useApolloClient();
const cachedTask = client.readFragment({
id: `Activity:${task.id}`,
fragment: ACTIVITY_UPDATE_FRAGMENT,
const { updateOneObject } = useUpdateOneObjectRecord({
objectNameSingular: 'activityV2',
});
const completeTask = useCallback(
(value: boolean) => {
const completedAt = value ? new Date().toISOString() : null;
updateActivityMutation({
variables: {
where: { id: task.id },
data: {
completedAt,
},
updateOneObject?.({
idToUpdate: task.id,
input: {
completedAt,
},
optimisticResponse: {
__typename: 'Mutation',
updateOneActivity: {
...cachedTask,
completedAt,
},
},
refetchQueries: [getOperationName(GET_ACTIVITIES) ?? ''],
});
},
[cachedTask, task.id, updateActivityMutation],
[task.id, updateOneObject],
);
return {

View File

@ -3,40 +3,46 @@ import { useRecoilState, useRecoilValue } from 'recoil';
import { currentUserState } from '@/auth/states/currentUserState';
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
import { useFindManyObjectRecords } from '@/object-record/hooks/useFindManyObjectRecords';
import { turnFilterIntoWhereClause } from '@/ui/object/object-filter-dropdown/utils/turnFilterIntoWhereClause';
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
import { ActivityType, useGetActivitiesQuery } from '~/generated/graphql';
import { SortOrder } from '~/generated/graphql';
import { ActivityType } from '~/generated-metadata/graphql';
import { parseDate } from '~/utils/date-utils';
export const useCurrentUserTaskCount = () => {
const [currentUser] = useRecoilState(currentUserState);
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
const { data } = useGetActivitiesQuery({
variables: {
where: {
type: { equals: ActivityType.Task },
completedAt: { equals: null },
...(currentUser
? turnFilterIntoWhereClause({
fieldMetadataId: 'assigneeId',
value: currentUser.id,
operand: ViewFilterOperand.Is,
displayValue:
currentWorkspaceMember?.firstName +
' ' +
currentWorkspaceMember?.lastName,
displayAvatarUrl: currentWorkspaceMember?.avatarUrl ?? undefined,
definition: {
type: 'ENTITY',
},
})
: {}),
},
const { objects } = useFindManyObjectRecords({
objectNamePlural: 'activitiesV2',
filter: {
type: { equals: ActivityType.Task },
completedAt: { equals: null },
...(currentUser
? turnFilterIntoWhereClause({
fieldMetadataId: 'assigneeId',
value: currentUser.id,
operand: ViewFilterOperand.Is,
displayValue:
currentWorkspaceMember?.firstName +
' ' +
currentWorkspaceMember?.lastName,
displayAvatarUrl: currentWorkspaceMember?.avatarUrl ?? undefined,
definition: {
type: 'ENTITY',
},
})
: {}),
},
orderBy: [
{
createdAt: SortOrder.Desc,
},
],
});
const currentUserDueTaskCount = data?.findManyActivities.filter((task) => {
const currentUserDueTaskCount = objects.filter((task) => {
if (!task.dueAt) {
return false;
}

View File

@ -1,9 +1,11 @@
import { DateTime } from 'luxon';
import { Activity } from '@/activities/types/Activity';
import { ActivityTargetableEntity } from '@/activities/types/ActivityTargetableEntity';
import { useFindManyObjectRecords } from '@/object-record/hooks/useFindManyObjectRecords';
import { useFilter } from '@/ui/object/object-filter-dropdown/hooks/useFilter';
import { turnFilterIntoWhereClause } from '@/ui/object/object-filter-dropdown/utils/turnFilterIntoWhereClause';
import { ActivityType, useGetActivitiesQuery } from '~/generated/graphql';
import { SortOrder } from '~/generated/graphql';
import { parseDate } from '~/utils/date-utils';
export const useTasks = (entity?: ActivityTargetableEntity) => {
@ -22,62 +24,64 @@ export const useTasks = (entity?: ActivityTargetableEntity) => {
}
: Object.assign({}, turnFilterIntoWhereClause(selectedFilter));
const { data: completeTasksData } = useGetActivitiesQuery({
variables: {
where: {
type: { equals: ActivityType.Task },
completedAt: { not: { equals: null } },
...whereFilters,
},
},
const { objects: completeTasksData } = useFindManyObjectRecords({
objectNamePlural: 'activitiesV2',
skip: !entity && !selectedFilter,
filter: {
type: { equals: 'Task' },
completedAt: { not: { equals: null } },
...whereFilters,
},
orderBy: [
{
createdAt: SortOrder.Desc,
},
],
});
const { data: incompleteTaskData } = useGetActivitiesQuery({
variables: {
where: {
type: { equals: ActivityType.Task },
completedAt: { equals: null },
...whereFilters,
},
},
const { objects: incompleteTaskData } = useFindManyObjectRecords({
objectNamePlural: 'activitiesV2',
skip: !entity && !selectedFilter,
filter: {
type: { equals: 'Task' },
completedAt: { equals: null },
...whereFilters,
},
orderBy: [
{
createdAt: SortOrder.Desc,
},
],
});
const todayOrPreviousTasks = incompleteTaskData?.findManyActivities.filter(
(task) => {
if (!task.dueAt) {
return false;
}
const dueDate = parseDate(task.dueAt).toJSDate();
const today = DateTime.now().endOf('day').toJSDate();
return dueDate <= today;
},
);
const todayOrPreviousTasks = incompleteTaskData?.filter((task) => {
if (!task.dueAt) {
return false;
}
const dueDate = parseDate(task.dueAt).toJSDate();
const today = DateTime.now().endOf('day').toJSDate();
return dueDate <= today;
});
const upcomingTasks = incompleteTaskData?.findManyActivities.filter(
(task) => {
if (!task.dueAt) {
return false;
}
const dueDate = parseDate(task.dueAt).toJSDate();
const today = DateTime.now().endOf('day').toJSDate();
return dueDate > today;
},
);
const upcomingTasks = incompleteTaskData?.filter((task) => {
if (!task.dueAt) {
return false;
}
const dueDate = parseDate(task.dueAt).toJSDate();
const today = DateTime.now().endOf('day').toJSDate();
return dueDate > today;
});
const unscheduledTasks = incompleteTaskData?.findManyActivities.filter(
(task) => {
return !task.dueAt;
},
);
const unscheduledTasks = incompleteTaskData?.filter((task) => {
return !task.dueAt;
});
const completedTasks = completeTasksData?.findManyActivities;
const completedTasks = completeTasksData;
return {
todayOrPreviousTasks: todayOrPreviousTasks ?? [],
upcomingTasks: upcomingTasks ?? [],
unscheduledTasks: unscheduledTasks ?? [],
completedTasks: completedTasks ?? [],
todayOrPreviousTasks: (todayOrPreviousTasks ?? []) as Activity[],
upcomingTasks: (upcomingTasks ?? []) as Activity[],
unscheduledTasks: (unscheduledTasks ?? []) as Activity[],
completedTasks: (completedTasks ?? []) as Activity[],
};
};