diff --git a/web-server/pages/api/resources/orgs/[org_id]/teams/index.ts b/web-server/pages/api/resources/orgs/[org_id]/teams/index.ts index c88e3f2da..f5a9c3f64 100644 --- a/web-server/pages/api/resources/orgs/[org_id]/teams/index.ts +++ b/web-server/pages/api/resources/orgs/[org_id]/teams/index.ts @@ -1,17 +1,16 @@ +import { groupBy, prop } from 'ramda'; import * as yup from 'yup'; import { getAllTeamsReposProdBranchesForOrg, transformTeamRepoBranchesToMap } from '@/api/internal/team/[team_id]/repo_branches'; +import { getTeamRepos } from '@/api/resources/team_repos'; import { Endpoint } from '@/api-helpers/global'; import { getTeamMembersFilterSettingForOrg } from '@/api-helpers/team'; -import { getMiniUsersByOrgId } from '@/api-helpers/user'; import { getTeamV2Mock } from '@/mocks/teams'; import { FetchTeamsResponse } from '@/types/resources'; import { db } from '@/utils/db'; -import groupBy from '@/utils/objectArray'; - const getSchema = yup.object().shape({ user_id: yup.string().uuid().nullable().optional(), include_teams: yup.array().of(yup.string().uuid()).nullable().optional() @@ -54,9 +53,9 @@ export const getOrgTeams = async ( {} as Record ); - const [users_map, teamsReposProductionBranchDetails] = await Promise.all([ - getMiniUsersByOrgId(org_id).then(groupBy), - getAllTeamsReposProdBranchesForOrg(org_id) + const [teamsReposProductionBranchDetails, repos] = await Promise.all([ + getAllTeamsReposProdBranchesForOrg(org_id), + Promise.all(teamRows.map((team) => getTeamRepos(team.id))) ]); const teamManagers = {} as Record; @@ -74,12 +73,15 @@ export const getOrgTeams = async ( t.manager_id === user_id || t.member_ids.includes(user_id) ); - const teamReposProdBranchMap = transformTeamRepoBranchesToMap( teamsReposProductionBranchDetails ); - return { teams, users: users_map, teamReposProdBranchMap }; + return { + teams, + teamReposProdBranchMap, + teamReposMap: groupBy(prop('team_id'), repos.flat()) + }; }; export default endpoint.serve(); diff --git a/web-server/pages/api/resources/orgs/[org_id]/teams/v2.ts b/web-server/pages/api/resources/orgs/[org_id]/teams/v2.ts index 3f7ebb434..38c0ad0f2 100644 --- a/web-server/pages/api/resources/orgs/[org_id]/teams/v2.ts +++ b/web-server/pages/api/resources/orgs/[org_id]/teams/v2.ts @@ -151,7 +151,7 @@ endpoint.handle.PATCH(patchSchema, async (req, res) => { return res.send(getTeamV2Mock); } - const { org_id, id, name, org_repos, provider } = req.payload; + const { id, name, org_repos, provider } = req.payload; const orgReposList: ReqRepoWithProvider[] = []; forEachObjIndexed((repos, org) => { repos.forEach((repo) => { diff --git a/web-server/pages/welcome.tsx b/web-server/pages/welcome.tsx index 9f19fb642..0d4fef42b 100644 --- a/web-server/pages/welcome.tsx +++ b/web-server/pages/welcome.tsx @@ -1,5 +1,6 @@ import { Button, Card, Box, styled, Container } from '@mui/material'; import Head from 'next/head'; +import { useRouter } from 'next/router'; import { ReactNode } from 'react'; import background from '@/assets/background.png'; @@ -12,6 +13,10 @@ import { FlexBox } from '@/components/FlexBox'; import { Logo } from '@/components/Logo/Logo'; import { Line } from '@/components/Text'; import { ROUTES } from '@/constants/routes'; +import { useAuth } from '@/hooks/useAuth'; +import { updateOnboardingState } from '@/slices/auth'; +import { useDispatch } from '@/store'; +import { OnboardingStep } from '@/types/resources'; function Page() { return ( @@ -60,6 +65,10 @@ const containerStyles = { }; const OnboardingContent = () => { + const dispatch = useDispatch(); + const router = useRouter(); + const { onboardingState, orgId } = useAuth(); + return ( @@ -111,7 +120,24 @@ const OnboardingContent = () => { ))} - diff --git a/web-server/src/components/TeamSelector/useTeamSelectorSetup.tsx b/web-server/src/components/TeamSelector/useTeamSelectorSetup.tsx index 763accd02..62966ae1c 100644 --- a/web-server/src/components/TeamSelector/useTeamSelectorSetup.tsx +++ b/web-server/src/components/TeamSelector/useTeamSelectorSetup.tsx @@ -10,7 +10,6 @@ import { useAuth } from '@/hooks/useAuth'; import { useAxios } from '@/hooks/useAxios'; import { useStateTeamConfig } from '@/hooks/useStateTeamConfig'; import { appSlice } from '@/slices/app'; -import { resourcesSlice } from '@/slices/resources'; import { teamSlice } from '@/slices/team'; import { useSelector } from '@/store'; import { Team } from '@/types/api/teams'; @@ -65,6 +64,7 @@ export const useTeamSelectorSetup = ({ mode }: UseTeamSelectorSetupArgs) => { const updateUsers = useCallback( (res: AxiosResponse) => { dispatch(teamSlice.actions.setTeams(res.data.teams)); + dispatch(teamSlice.actions.setTeamReposMaps(res.data.teamReposMap)); dispatch( appSlice.actions.setTeamProdBranchMap(res.data.teamReposProdBranchMap) ); @@ -102,19 +102,12 @@ export const useTeamSelectorSetup = ({ mode }: UseTeamSelectorSetupArgs) => { onSuccess: updateUsers }); - useEffect(() => { - dispatch(resourcesSlice.actions.updateFetchState({ users: fetch_state })); - }, [dispatch, fetch_state]); - const apiTeams = useMemo( () => payload?.teams || ([] as Team[]), [payload?.teams] ); - const usersMap = useMemo( - () => payload?.users || ([] as unknown as FetchTeamsResponse['users']), - [payload?.users] - ); + const usersMap = {}; useEffect(() => { if (!orgId) return; diff --git a/web-server/src/hooks/useStateTeamConfig.tsx b/web-server/src/hooks/useStateTeamConfig.tsx index 1834df0ee..4bdaff8d1 100644 --- a/web-server/src/hooks/useStateTeamConfig.tsx +++ b/web-server/src/hooks/useStateTeamConfig.tsx @@ -6,7 +6,6 @@ import { startOfWeek } from 'date-fns'; import { daysInWeek } from 'date-fns/constants'; -import { ascend, compose, partition, prop, sort, toLower } from 'ramda'; import { useCallback, useMemo } from 'react'; import { DateRange, DateRangeMap } from '@/components/DateRangePicker'; @@ -168,32 +167,6 @@ export const useStateBranchConfig = () => { return branchNames; }; -export const useStateSingleTeamMembers = (includeManager: boolean = false) => { - const { team } = useSingleTeamConfig(); - - const usersMap = useSelector((s) => s.resources.users); - - return useMemo(() => { - const ids = [ - ...(team?.member_ids || []), - includeManager ? team?.manager_id : null - ].filter(Boolean); - - let users = ids - .filter((id) => Boolean(usersMap[id])) - .map((id) => ({ - ...usersMap[id], - isManager: id === team?.manager_id - })); - - users = sort(ascend(compose(toLower, prop('name'))), users) as typeof users; - - const [mgr, others] = partition((user) => user.isManager, users); - - return [...mgr, ...others].filter(Boolean); - }, [includeManager, team?.manager_id, team?.member_ids, usersMap]); -}; - export const useCurrentDateRangeReactNode = () => { const { start, end, partiallyUnselected } = useStateDateConfig(); return !partiallyUnselected ? ( diff --git a/web-server/src/slices/auth.ts b/web-server/src/slices/auth.ts index d81e4cf67..ebc2f7209 100644 --- a/web-server/src/slices/auth.ts +++ b/web-server/src/slices/auth.ts @@ -3,6 +3,7 @@ import { PayloadAction, createAsyncThunk } from '@reduxjs/toolkit'; import { handleApi } from '@/api-helpers/axios-api-instance'; import { FetchState } from '@/constants/ui-states'; +import { OnboardingStep } from '@/types/resources'; import { addFetchCasesToReducer } from '@/utils/redux'; export interface State { @@ -46,6 +47,19 @@ export const authSlice = createSlice({ state.org = action.payload; } ); + addFetchCasesToReducer( + builder, + updateOnboardingState, + 'org', + ( + state, + action: PayloadAction<{ onboarding_state: OnboardingStep[] }> + ) => { + if (state.org) { + state.org.onboarding_state = action.payload.onboarding_state; + } + } + ); } }); @@ -56,3 +70,18 @@ export const fetchCurrentOrg = createAsyncThunk( return session.org; } ); + +export const updateOnboardingState = createAsyncThunk( + 'auth/updateOnboardingState', + async (params: { org_id: ID; onboardingState: OnboardingStep[] }) => { + return handleApi<{ onboarding_state: OnboardingStep[] }>( + `/resources/orgs/${params.org_id}/onboarding`, + { + method: 'PUT', + data: { + onboarding_state: params.onboardingState + } + } + ); + } +); diff --git a/web-server/src/slices/resources.ts b/web-server/src/slices/resources.ts deleted file mode 100644 index 082bf9097..000000000 --- a/web-server/src/slices/resources.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { createSlice } from '@reduxjs/toolkit'; - -import { Row } from '@/constants/db'; -import { Team } from '@/types/api/teams'; -import { StateFetchConfig } from '@/types/redux'; - -import type { PayloadAction } from '@reduxjs/toolkit'; - -type State = StateFetchConfig<{ - teams: Record; - teamReposMaps: Record & Row<'OrgRepo'>)[]>; -}>; - -const initialState: State = { - teams: {}, - teamReposMaps: {} -}; - -export const resourcesSlice = createSlice({ - name: 'resources', - initialState, - reducers: { - updateFetchState( - state: State, - action: PayloadAction> - ): void { - state.requests = { - ...(action.payload as State['requests']) - }; - }, - updateTeams( - state: State, - action: PayloadAction> - ): void { - state.teams = { - ...state.teams, - ...action.payload - }; - } - }, - extraReducers: (_builder) => {} -}); diff --git a/web-server/src/store/rootReducer.ts b/web-server/src/store/rootReducer.ts index a7794a48b..ed0c90f35 100644 --- a/web-server/src/store/rootReducer.ts +++ b/web-server/src/store/rootReducer.ts @@ -7,13 +7,11 @@ import { doraMetricsSlice } from '@/slices/dora_metrics'; import { loadLinkSlice } from '@/slices/loadLink'; import { orgSlice } from '@/slices/org'; import { reposSlice } from '@/slices/repos'; -import { resourcesSlice } from '@/slices/resources'; import { teamSlice } from '@/slices/team'; export const rootReducer = combineReducers({ app: appSlice.reducer, auth: authSlice.reducer, - resources: resourcesSlice.reducer, actions: actionsSlice.reducer, team: teamSlice.reducer, repos: reposSlice.reducer, diff --git a/web-server/src/types/resources.ts b/web-server/src/types/resources.ts index b77b5444d..380de3d27 100644 --- a/web-server/src/types/resources.ts +++ b/web-server/src/types/resources.ts @@ -4,6 +4,7 @@ import { ReactChild, ReactFragment, ReactPortal } from 'react'; import { Row } from '@/constants/db'; import { CIProvider, Integration } from '@/constants/integrations'; +import { DB_OrgRepo } from '@/types/api/org_repo'; import { Team } from '@/types/api/teams'; export type DeepPartial = { @@ -611,8 +612,8 @@ export enum TeamSettings { export type FetchTeamsResponse = { teams: Team[]; - users: Record; teamReposProdBranchMap: Record; + teamReposMap: Record; }; export type FetchTeamSettingsAPIResponse = {