From b18a1314dbc6b0dea0bbbb581f18ad5affddebb0 Mon Sep 17 00:00:00 2001 From: Vijay Joshi Date: Fri, 20 Oct 2023 13:04:48 +0530 Subject: [PATCH] TP-42065 : UI for add team oncall and psec oncall, show team oncall, psec oncall, removal of user type, separation of update types, and other update team UI changes (#64) * TP-4206 : API integration for add psec oncall and dev oncall * TP-42065 : Dropdown UI for team oncall and psec oncall * TP-42065 : Dropdown UI for team oncall and psec oncall * Move bot fetching to page level from componenet * Minor changes * Updated update team ui * Move bots fetching call to a separate file * Remove uncesessary props * PR Review Fixes * Remove changes from other branch * Build failure fix and Api timing issue fix * Design signoff changes * Changes after second design review * Changes after third design review * PR Review Changes * More PR reviews and rebase --- package-lock.json | 0 .../DrawerMode/DrawerMode.module.scss | 2 +- src/Pages/Team/Team.module.scss | 88 +++++- src/Pages/Team/bots.ts | 23 ++ src/Pages/Team/constants.ts | 11 + src/Pages/Team/index.tsx | 2 + src/Pages/Team/partials/TeamForm.tsx | 292 +++++++++++++----- src/Pages/Team/partials/TeamResultsTable.tsx | 18 +- .../MembersDetails/Members.module.scss | 1 + src/components/MembersDetails/index.tsx | 18 +- 10 files changed, 350 insertions(+), 105 deletions(-) create mode 100644 package-lock.json create mode 100644 src/Pages/Team/bots.ts diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..e69de29 diff --git a/src/Pages/Incidents/DrawerMode/DrawerMode.module.scss b/src/Pages/Incidents/DrawerMode/DrawerMode.module.scss index 54d5787..14cc4cc 100644 --- a/src/Pages/Incidents/DrawerMode/DrawerMode.module.scss +++ b/src/Pages/Incidents/DrawerMode/DrawerMode.module.scss @@ -33,7 +33,7 @@ a { text-decoration: none; - color: #24b4d2; + color: var(--navi-color-blue-base); } } diff --git a/src/Pages/Team/Team.module.scss b/src/Pages/Team/Team.module.scss index 3c92487..ff8faaa 100644 --- a/src/Pages/Team/Team.module.scss +++ b/src/Pages/Team/Team.module.scss @@ -21,6 +21,15 @@ } .custom-bordered-input { margin-top: 20px; + display: block; +} + +.info-icon { + margin: -2.5px 4px; +} + +.slack-details-header { + margin-bottom: 18px; } .custom-textarea { @@ -35,6 +44,40 @@ padding: 6px 0; } +.slack-details-wrapper { + margin-top: 16px; +} + +.slack-property-name { + display: inline; + width: 50%; +} + +.slack-channel-wrapper { + float: right; + text-align: right; +} + +.channel-name-detail { + float: right; + text-align: right; +} + +.slack-property-detail { + display: inline; + width: 50%; + float: right; + text-align: right; + color: black; + font-weight: 500; + line-height: 20px; + word-wrap: break-word; +} + +.slack-channel-content { + text-align: right; +} + .team-name-wrapper { display: flex; align-items: center; @@ -47,7 +90,10 @@ .update-team-btn { width: fit-content; - margin-top: 12px; + border: 1px solid var(--navi-color-blue-base); + color: var(--navi-color-blue-base); + float: right; + margin: 12px 0px; } .create-team-btn-wrapper { padding: 6px 0 12px 0px; @@ -64,7 +110,13 @@ .vertical-line { transform: rotateX(180deg); - border: 1px solid #e8e8e8; + border: 0.5px solid var(--navi-color-gray-border); +} + +.horizontal-line { + height: 1px; + background: var(--navi-color-gray-border); + margin-top: 50px; } .loader-container { @@ -76,13 +128,27 @@ .accordion-header { display: flex; - align-items: center; - justify-content: space-between; height: fit-content; width: 100%; - .title { - padding: 12px; + .team-name { + margin: 16px 3px; + font-weight: 400; + font-size: 16px; + line-height: 18px; } + .updated-at { + border: 1px solid var(--navi-color-gray-border); + border-radius: 8px; + padding: 2px 8px; + margin-right: 8px; + } +} + +.add-member-btn { + border: 1px solid var(--navi-color-blue-base); + color: var(--navi-color-blue-base); + float: right; + margin: 12px 0px; } .team-header-wrapper { @@ -122,3 +188,13 @@ margin-bottom: 20px; gap: 0 8px; } + +.team-input::placeholder { + color: var(--navi-color-navigation-blue-c2); +} + +.oncall-selector { + width: 100%; + margin-top: 8px; + height: 38px; +} diff --git a/src/Pages/Team/bots.ts b/src/Pages/Team/bots.ts new file mode 100644 index 0000000..6a6b5c4 --- /dev/null +++ b/src/Pages/Team/bots.ts @@ -0,0 +1,23 @@ +import { ApiService } from '@src/services/api'; +import { FETCH_ALL_BOTS_DATA, PickerOptionProps } from './constants'; +import { toast } from '@navi/web-ui/lib/primitives/Toast'; + +let bots: Array = []; + +export const getBots = (): Array => bots; + +export const fetchAllBots = (): void => { + ApiService.get(FETCH_ALL_BOTS_DATA) + .then(response => { + bots = []; + response?.data?.data.map(data => { + bots.push({ + label: '@' + data.name, + value: data.id, + }); + }); + }) + .catch(error => { + toast.error(error?.message); + }); +}; diff --git a/src/Pages/Team/constants.ts b/src/Pages/Team/constants.ts index caf5b82..2b70b7e 100644 --- a/src/Pages/Team/constants.ts +++ b/src/Pages/Team/constants.ts @@ -1,4 +1,5 @@ export const FETCH_TEAM_DATA = `${window?.config?.BASE_API_URL}/teams`; +export const FETCH_ALL_BOTS_DATA = `${window?.config?.BASE_API_URL}/houston/bots`; export const CREATE_TEAM = `${window?.config?.BASE_API_URL}/houston/teams/add`; export const FETCH_SINGLE_TEAM_DATA = (payload: string): string => { @@ -29,6 +30,11 @@ export interface TeamsData { expand: boolean; } +export interface BotsData { + id: string; + name: string; +} + export interface TeamFormProps { teamId: string; isExpanded: boolean; @@ -56,3 +62,8 @@ export interface CreateTeamProps { startTeamSearch: (id: number) => void; setOpen: (open: boolean) => void; } + +export interface PickerOptionProps { + label: string; + value: string; +} diff --git a/src/Pages/Team/index.tsx b/src/Pages/Team/index.tsx index ee0c722..5878307 100644 --- a/src/Pages/Team/index.tsx +++ b/src/Pages/Team/index.tsx @@ -10,6 +10,7 @@ import styles from './Team.module.scss'; import Button from '@navi/web-ui/lib/primitives/Button'; import { AddIcon } from '@navi/web-ui/lib/icons'; import { useAuthData } from './Hook'; +import { fetchAllBots } from './bots'; const Team: FC = () => { const [data, setData] = useState([]); @@ -50,6 +51,7 @@ const Team: FC = () => { }; useEffect(() => { + fetchAllBots(); startTeamSearch(); }, []); diff --git a/src/Pages/Team/partials/TeamForm.tsx b/src/Pages/Team/partials/TeamForm.tsx index bc35ed5..46b3ecb 100644 --- a/src/Pages/Team/partials/TeamForm.tsx +++ b/src/Pages/Team/partials/TeamForm.tsx @@ -3,31 +3,36 @@ import { useEffect, useState } from 'react'; import LoadingIcon from '@navi/web-ui/lib/icons/LoadingIcon'; import Button from '@navi/web-ui/lib/primitives/Button'; import { toast } from '@navi/web-ui/lib/primitives/Toast'; -import { BorderedInput, Typography } from '@navi/web-ui/lib/primitives'; -import { Filter } from '@navi/web-ui/lib/components'; -import SlackIcon from '@src/assets/SlackIcon'; +import { + BorderedInput, + Tooltip, + Typography, +} from '@navi/web-ui/lib/primitives'; +import { InfoIcon } from '@navi/web-ui/lib/icons'; import { FETCH_SINGLE_TEAM_DATA, TeamFormProps, UPDATE_TEAM_DATA, - slackUserOptions, - userInputPlaceholders, } from '../constants'; import { ApiService } from '@src/services/api'; import MembersDetails from '@src/components/MembersDetails'; import DrawerStyles from '@src/Pages/Incidents/DrawerMode/DrawerMode.module.scss'; import styles from '../Team.module.scss'; +import { ConfigProvider, Select, ThemeConfig } from 'antd'; +import { getBots } from '../bots'; +import SlackIcon from '@src/assets/SlackIcon'; const TeamForm = (props: TeamFormProps) => { const { teamId, isExpanded, setTeamId, setLastUpdatedAt } = props; const [data, setData] = useState({}); - const [slackUserIds, setSlackUserIds] = useState(''); + const [slackUserEmails, setSlackUserEmails] = useState(''); const [isLoading, setIsLoading] = useState(false); const [slackChannelId, setSlackChannelId] = useState(''); - const [userType, setUserType] = useState('Email-id'); - const [updateloading, setUpdateloading] = useState(false); + const [oncallHandle, setOncallHandle] = useState(''); + const [psecOncallHandle, setPsecOncallHandle] = useState(''); + const [showTooltip, setShowTooltip] = useState(false); const fetchTeamById = (updateDate = false, showMainLoader = true) => { const endPoint = FETCH_SINGLE_TEAM_DATA(teamId); @@ -58,29 +63,39 @@ const TeamForm = (props: TeamFormProps) => { } }, [teamId, isExpanded]); - const submitHandler = () => { + const addMemberHandler = (): void => { const endPoint = UPDATE_TEAM_DATA(); - const slackIds = - data?.participants?.map(participant => participant?.id) || []; - const finalSlackData = slackUserIds?.includes(',') - ? slackUserIds.split(',').map(item => item?.trim()) - : [slackUserIds]; - const userIds = - userType === slackUserOptions[0].label - ? { - workEmailIds: finalSlackData, - } - : { - slackUserIds: finalSlackData, - }; + const finalSlackData = slackUserEmails?.includes(',') + ? slackUserEmails.split(',').map(item => item?.trim()) + : [slackUserEmails]; ApiService.post(endPoint, { id: teamId, - ...userIds, - webhook_slack_channel: slackChannelId, + workEmailIds: finalSlackData, + }) + .then(response => { + toast.success(response?.data?.data); + fetchTeamById(true); + }) + .catch(error => { + const toastMessage = `${ + error?.response?.data?.error?.message + ? `${error?.response?.data?.error?.message}` + : '' + }`; + toast.error(toastMessage); + }); + }; + + const submitHandler = (): void => { + const endPoint = UPDATE_TEAM_DATA(); + ApiService.post(endPoint, { + id: teamId, + webhook_slack_channel: slackChannelId, + on_call_handle: oncallHandle, + pse_on_call_id: psecOncallHandle, }) .then(response => { toast.success(response?.data?.data); - setUpdateloading(true); fetchTeamById(true, false); }) .catch(error => { @@ -93,35 +108,58 @@ const TeamForm = (props: TeamFormProps) => { }); }; - const getSubmitButtonState = (): boolean => { - if (slackUserIds.length) { - return !slackUserIds.length; - } - return !slackChannelId.length; + const filterOption = (input: string, option): boolean => + (option?.label ?? '').toLowerCase().includes(input.toLowerCase()); + + const dropdownTheme: ThemeConfig = { + token: { + colorTextPlaceholder: 'var(--navi-color-navigation-blue-c2)', + borderRadius: 8, + colorBorder: 'var(--navi-bordered-input-input-wrapper-border-default)', + fontSize: 14, + }, }; - const handleFilterChange = option => { - setUserType(option?.label); + const getSubmitButtonState = (): boolean => { + if (oncallHandle?.length) { + return !oncallHandle.length; + } + if (psecOncallHandle?.length) { + return !psecOncallHandle.length; + } + return !slackChannelId?.length; + }; + + const getAddMemberButtonState = (): boolean => { + return !slackUserEmails.length; }; const returnSlackChannel = () => { - return data?.webhookSlackChannelName && data?.webhookSlackChannelId ? ( -
- - + return data?.webhookSlackChannelName != 'not found' && + data?.webhookSlackChannelId ? ( + ) : ( - '-' + + - + ); }; @@ -138,18 +176,57 @@ const TeamForm = (props: TeamFormProps) => {
- - Slack Channel Name: + + Slack details - {returnSlackChannel()} +
+ + Channel + + {returnSlackChannel()} +
+
+ + Team on call + + + {data?.oncall && data?.oncall?.name != '' + ? '@' + data?.oncall?.name + : '-'} + +
+
+ + PSEC on call + + + {data?.pse_oncall && data?.pse_oncall?.name != '' + ? '@' + data?.pse_oncall?.name + : '-'} + +
- - Members: + + Members @@ -157,56 +234,111 @@ const TeamForm = (props: TeamFormProps) => {

+
- {updateloading && ( -
- -
- )}
- - Add members + + Add member(s) -
- - Choose user type: - - -
setSlackUserIds(e.target.value)} - hintMsg="Please enter the values separated by commas." - disabled={!userType.length} + placeholder={'Enter email ids'} + onChange={e => setSlackUserEmails(e.target.value)} + hintMsg="Please enter the emails separated by commas." fullWidth + className={styles['team-input']} /> + +

+
+
+
+ + Slack details + + + Channel I.D. + { + setShowTooltip(true); + }} + onMouseLeave={() => { + setShowTooltip(false); + }} + className={styles['info-icon']} + /> + + setSlackChannelId(e.target?.value)} + fullWidth + className={styles['team-input']} + /> +
- setSlackChannelId(e.target?.value)} - hintMsg="Add the slack channel to get incident updates." - fullWidth - /> + + Team on call + + + setPsecOncallHandle(e)} + className={styles['oncall-selector']} + allowClear + /> + +
+
diff --git a/src/Pages/Team/partials/TeamResultsTable.tsx b/src/Pages/Team/partials/TeamResultsTable.tsx index d5749f9..92df3c5 100644 --- a/src/Pages/Team/partials/TeamResultsTable.tsx +++ b/src/Pages/Team/partials/TeamResultsTable.tsx @@ -32,18 +32,16 @@ const TeamResultsTable = (props: TeamResultsTableProps) => { expanded={team?.expand || team.id === teamId} header={
- + {team?.name} - {team?.lastUpdatedAt && ( - - Updated At: {returnDate(team?.lastUpdatedAt)} - - )} + + ({team?.slackUserIds?.length}) +
} > diff --git a/src/components/MembersDetails/Members.module.scss b/src/components/MembersDetails/Members.module.scss index d2dc6f7..84ebb87 100644 --- a/src/components/MembersDetails/Members.module.scss +++ b/src/components/MembersDetails/Members.module.scss @@ -13,6 +13,7 @@ .participant-detail-nest { display: flex; + margin-right: 10px; } .remove-logo { diff --git a/src/components/MembersDetails/index.tsx b/src/components/MembersDetails/index.tsx index d0d7296..0fcf672 100644 --- a/src/components/MembersDetails/index.tsx +++ b/src/components/MembersDetails/index.tsx @@ -165,9 +165,9 @@ const MembersDetails = (props: any) => {
-
- {showRemoveButton && - !(participant.email === managerEmail) && ( + {showRemoveButton && + !(participant.email === managerEmail) && ( +
{ />
- )} -
+
+ )} -
- {participant.email === managerEmail && } -
+ {participant.email === managerEmail && ( +
+ +
+ )} {showRemoveButton && !(participant.email === managerEmail) && (