-
Notifications
You must be signed in to change notification settings - Fork 8.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Manage Team ooo or crud and fetch past ooo records #16456
base: main
Are you sure you want to change the base?
feat: Manage Team ooo or crud and fetch past ooo records #16456
Conversation
@vijayraghav-io is attempting to deploy a commit to the cal Team on Vercel. A member of the Team first needs to authorize it. |
Graphite Automations"Add consumer team as reviewer" took an action on this PR • (09/02/24)1 reviewer was added to this PR based on Keith Williams's automation. "Add community label" took an action on this PR • (09/02/24)1 label was added to this PR based on Keith Williams's automation. "Add foundation team as reviewer" took an action on this PR • (09/23/24)1 reviewer was added to this PR based on Keith Williams's automation. |
interface OutOfOfficeEntry { | ||
id: number; | ||
uuid: string; | ||
start: Date; | ||
end: Date; | ||
toUserId: number | null; | ||
toUser: { | ||
username: string; | ||
} | null; | ||
reason: { | ||
id: number; | ||
emoji: string; | ||
reason: string; | ||
userId: number; | ||
} | null; | ||
notes: string | null; | ||
user: { id: number; avatarUrl: string; username: string; email: string } | null; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is defined twice, can you pls reuse it another component?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, it can be reused, will update
listMembers | ||
?.filter((member) => (oooType === "mine" ? me?.data?.id !== member.id : oooType === "team")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It’s better to use enum instead of hardcoded values like "mine" and "team."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
oooType={oooType} | ||
setTeamOOOEntriesUpdated={setTeamOOOEntriesUpdated} | ||
setMyOOOEntriesUpdated={setMyOOOEntriesUpdated} | ||
/> | ||
)} | ||
{oooType === "team" ? ( | ||
<OutOfOfficeEntriesListForTeam | ||
editOutOfOfficeEntry={editOutOfOfficeEntry} | ||
teamOOOEntriesUpdated={teamOOOEntriesUpdated} | ||
/> | ||
) : ( | ||
<OutOfOfficeEntriesList | ||
editOutOfOfficeEntry={editOutOfOfficeEntry} | ||
myOOOEntriesUpdated={myOOOEntriesUpdated} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are there separate components for Team and Mine view?
As far as I can tell both are same with same functionality and code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
they are similar, but differ in columns displayed. Wanted to avoid having many conditions within same file for team and mine and keep it separated , s
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
handled in single component
Unable to scroll Redirect To Member when editing an entry, can only scroll it while adding a new that too I have to close it and open it for it to work, can you also replicate it? Recording.2024-09-02.133726.mp4 |
: false, | ||
}, | ||
orderBy: { | ||
end: "desc", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Imo it is better to sort by start date rather than end.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
let deletingOooOfUserId = ctx.user.id; | ||
let deletingOooOfEmail = ctx.user.email; | ||
let deletingOooOfUserName = ctx.user.username; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like the variable names in the whole file; they need to be improved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i was trying to be more descriptive for purpose of new variables, updated, hope it is better now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great stuff as usual @vijayraghav-io , but this needs some more improvement.
For orgs I can add redirection from one team to another
Recording.2024-09-02.134712.mp4
const members = await prisma.membership.findMany({ | ||
where: { | ||
teamId: { | ||
in: teams.map((team) => team.teamId), | ||
}, | ||
userId: { | ||
not: ctx.user.id, | ||
}, | ||
}, | ||
select: { | ||
userId: true, | ||
}, | ||
}); | ||
if (members.length === 0) { | ||
throw new TRPCError({ code: "NOT_FOUND", message: "no_team_members" }); | ||
} | ||
fetchOOOEntriesForIds = members.map((member) => member.userId); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a very performance-reducing operation. Need to be improved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
start: "asc", | ||
}); | ||
|
||
const outOfOfficeEntries = await prisma.outOfOfficeEntry.findMany({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you not add _count in select for this, instead of having separate queries for count and actual data?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The first query gets the total count of matching records, while the second query fetches only limited records (say 10). I tried _count can't be used here.
import type { | ||
TOutOfOfficeDelete, | ||
TOutOfOfficeEntriesListSchema, | ||
TOutOfOfficeInputSchema, | ||
} from "./outOfOffice.schema"; | ||
|
||
// function getTeam() checks if there is a team where 'adminUserId' is admin or owner | ||
// and 'memberUserId' is a member. | ||
// If exists returns the first found such team. | ||
const getTeam = async (adminUserId: number, memberUserId: number) => { | ||
return await prisma.team.findFirst({ | ||
where: { | ||
AND: [ | ||
{ | ||
members: { | ||
some: { | ||
userId: adminUserId, | ||
role: { | ||
in: [MembershipRole.ADMIN, MembershipRole.OWNER], | ||
}, | ||
}, | ||
}, | ||
}, | ||
{ | ||
members: { | ||
some: { | ||
userId: memberUserId, | ||
}, | ||
}, | ||
}, | ||
], | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Too many changes in the backend inside a single file. We definitely need to add tests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added Tests
export const OutOfOfficeEntriesListForTeam = ({ | ||
editOutOfOfficeEntry, | ||
teamOOOEntriesUpdated, | ||
}: { | ||
editOutOfOfficeEntry: (entry: BookingRedirectForm) => void; | ||
teamOOOEntriesUpdated: number; | ||
}) => { | ||
const { t } = useLocale(); | ||
const tableContainerRef = useRef<HTMLDivElement>(null); | ||
const [debouncedSearchTerm, setDebouncedSearchTerm] = useState(""); | ||
const [deletedEntry, setDeletedEntry] = useState(0); | ||
const { data, isPending, fetchNextPage, isFetching, refetch } = | ||
trpc.viewer.outOfOfficeEntriesList.useInfiniteQuery( | ||
{ | ||
limit: 10, | ||
fetchTeamMembersEntries: true, | ||
searchTerm: debouncedSearchTerm, | ||
}, | ||
{ | ||
getNextPageParam: (lastPage) => lastPage.nextCursor, | ||
placeholderData: keepPreviousData, | ||
} | ||
); | ||
|
||
useEffect(() => { | ||
refetch(); | ||
}, [teamOOOEntriesUpdated, deletedEntry, refetch]); | ||
|
||
const totalDBRowCount = data?.pages?.[0]?.meta?.totalRowCount ?? 0; | ||
//Flatten the array of arrays from the useInfiniteQuery hook | ||
const flatData = useMemo( | ||
() => data?.pages?.flatMap((page) => page.rows) ?? [], | ||
[data] | ||
) as OutOfOfficeEntry[]; | ||
const totalFetched = flatData.length; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey, this is similar to the other component. I know there are a few different cases that don't match, but instead of doing the same things twice in two different components, can you please try to consolidate them into a single component? If things become too difficult and there are too many visible conditional changes, it's okay to define 2 components. However, in such cases, define things once and use them in another component. For example, EmptyScreen is defined twice, etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
handled in single component
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work @vijayraghav-io , don't test it locally but codewise I've some doubt.
Thankyou! 🙏 @Amit91848 @anikdhabal , sure will address the comments. |
I checked multiple times, not able to recreate this for me. Able to search the list of members for redirect also. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't review the code but tested it locally, found the following issues:
- We need rounded corners in both my and team OOO:
- Non-admins/owners should not see the Team OOO tab at all
- Can we show past OOO in different tab called 'previous'?
As described here: [CAL-4527] OOO: Show your own history and give Admins CRUD and see all team members history #16333 (comment)
} | ||
columns.push({ | ||
id: "outOfOffice", | ||
header: `OutOfOffice (${totalDBRowCount})`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be 'Out of office' with a translation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
The latest updates on your projects. Learn more about Vercel for Git ↗︎ 2 Skipped Deployments
|
@anikdhabal , @Praashh resolved conflicts, updated tests due to changes from merges. |
…6333_teamOOOCrud
…6333_teamOOOCrud
@vijayraghav-io great works man. But I am thinking of completely transferring all the E2E tests related to OOO into unit tests. Could you go through all the OOO E2E tests and add them to your current test file along with the other tests? |
Thank you! @anikdhabal . |
If this is the case, then why are we adding tests to the handler here? Can't we add e2e tests instead to verify both the UI and functionalities for this PR? I think it would make sense to create a single test file for OOO and add e2e tests for this. Let's make the change then I've noticed that recent PRs failed due to OOO tests. Also, I have a query regarding that PR #18367, and we generally avoid any time dependency in e2e tests. |
Can you please recheck again, recent PRs don't have flakiness due to OOO tests. |
These are some of E2E results after OOO flakiness fix PR (#18367) was merged. This is the latest after above PR is reverted (OOO flakiness reappeared). |
@anikdhabal , updated OOO E2E tests to remove flakiness without time dependency in this new PR #18412 |
…6333_teamOOOCrud
…6333_teamOOOCrud
…6333_teamOOOCrud
@anikdhabal , resolved merge conflicts. Also, I tried to create E2E tests for Team OOO instead of current unit tests, but currently there is some playwright limitations for this.
So, I think currently we can go with unit tests for Team OOO and once we have the solution from playwright we can create E2E tests. PFB the Loom showing the issue with a team OOO E2E test, here i have manually zoomed out chromium browser while playwright is trying to reach down. (Here test is passing because of manul zoom out during test) https://www.loom.com/share/10a0e9474d534f1b9a99b0564a8b4e98?sid=16eab3c0-6281-4de3-b0af-63443c17dc04 Hope, with this all concerns are addressed. |
What does this PR do?
Approach to fetch past records:- Infinite scrolling with pagination is implemented to fetch additional records (10 at a time) when the user scrolls to the bottom of the table.
Also search by username and email is implemented to fetch past records of a member quickly.
https://www.loom.com/share/fe88b4739846419493fe26836daedf88?sid=96acca39-eaad-4fcc-89e9-c2153532e080
Mandatory Tasks (DO NOT REMOVE)