Skip to content

Commit

Permalink
Refactor user on-call assignments handling and visualization
Browse files Browse the repository at this point in the history
- Remove 'onCallSteps' field dependencies in user detail and replaced with 'onCallOverview' for better service count accuracy
- Refactor 'UserDetails.tsx', removed lodash dependency for cleaner and simpler data extraction
- Update 'serviceCount' function to directly read service count from the new 'onCallOverview' field
- Refactor 'UserOnCallAssignmentList.tsx' to adapt to the new data model
- Update step number representation to start from 0 instead of 1 to match back-end value
- Simplify interfaces and functions in 'UserOnCallAssignmentList.tsx' for generating service assignments data
  • Loading branch information
mastercactapus committed May 14, 2024
1 parent 9b5277f commit ff2ccc5
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 82 deletions.
2 changes: 1 addition & 1 deletion graphql2/graphqlapp/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func (a *User) OnCallOverview(ctx context.Context, obj *user.User) (*graphql2.On
for _, svc := range data {
svcCount[svc.ServiceID] = struct{}{}
overview.ServiceAssignments = append(overview.ServiceAssignments, graphql2.OnCallServiceAssignment{
StepNumber: int(svc.StepNumber) + 1,
StepNumber: int(svc.StepNumber),
EscalationPolicyID: svc.PolicyID.String(),
EscalationPolicyName: svc.PolicyName,
ServiceID: svc.ServiceID.String(),
Expand Down
44 changes: 9 additions & 35 deletions web/src/app/users/UserDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,12 @@ import { Grid } from '@mui/material'
import UserContactMethodCreateDialog from './UserContactMethodCreateDialog'
import UserNotificationRuleCreateDialog from './UserNotificationRuleCreateDialog'
import UserContactMethodVerificationDialog from './UserContactMethodVerificationDialog'
import _ from 'lodash'
import { GenericError, ObjectNotFound } from '../error-pages'
import { useSessionInfo } from '../util/RequireConfig'
import UserEditDialog from './UserEditDialog'
import UserDeleteDialog from './UserDeleteDialog'
import { QuerySetFavoriteButton } from '../util/QuerySetFavoriteButton'
import { EscalationPolicyStep } from '../../schema'
import { User } from '../../schema'
import { useIsWidthDown } from '../util/useWidth'
import UserShiftsCalendar from './UserShiftsCalendar'
import { useExpFlag } from '../util/useExpFlag'
Expand All @@ -35,15 +34,8 @@ const userQuery = gql`
contactMethods {
id
}
onCallSteps {
id
escalationPolicy {
id
assignedTo {
id
name
}
}
onCallOverview {
serviceCount
}
}
}
Expand All @@ -59,15 +51,8 @@ const profileQuery = gql`
contactMethods {
id
}
onCallSteps {
id
escalationPolicy {
id
assignedTo {
id
name
}
}
onCallOverview {
serviceCount
}
sessions {
id
Expand All @@ -76,17 +61,6 @@ const profileQuery = gql`
}
`

function serviceCount(onCallSteps: EscalationPolicyStep[] = []): number {
const svcs: { [Key: string]: boolean } = {}
;(onCallSteps || []).forEach((s) =>
(s?.escalationPolicy?.assignedTo || []).forEach(
(svc) => (svcs[svc.id] = true),
),
)

return Object.keys(svcs).length
}

export default function UserDetails(props: {
userID: string
readOnly: boolean
Expand All @@ -104,16 +78,16 @@ export default function UserDetails(props: {
const [showUserDeleteDialog, setShowUserDeleteDialog] = useState(false)
const mobile = useIsWidthDown('md')

const [{ data, error }] = useQuery({
const [{ data, error }] = useQuery<{ user: User }>({
query: isAdmin || userID === currentUserID ? profileQuery : userQuery,
variables: { id: userID },
})

const user = data?.user
if (error) return <GenericError error={error.message} />
if (!_.get(data, 'user.id')) return <ObjectNotFound />
if (!user) return <ObjectNotFound />

const user = _.get(data, 'user')
const svcCount = serviceCount(user.onCallSteps)
const svcCount = user.onCallOverview.serviceCount
const sessCount = user?.sessions?.length ?? 0

const disableNR = user.contactMethods.length === 0
Expand Down
68 changes: 22 additions & 46 deletions web/src/app/users/UserOnCallAssignmentList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,46 +4,24 @@ import { Card } from '@mui/material'
import FlatList from '../lists/FlatList'
import { sortBy, values } from 'lodash'
import { GenericError, ObjectNotFound } from '../error-pages'
import { OnCallServiceAssignment, User } from '../../schema'

const query = gql`
query userInfo($id: ID!) {
user(id: $id) {
id
name
onCallSteps {
id
stepNumber
escalationPolicy {
id
name
assignedTo {
id
name
}
onCallOverview {
serviceAssignments {
serviceID
serviceName
escalationPolicyName
stepNumber
}
}
}
}
`
interface QueryResult {
user: {
id: string
name: string
onCallSteps: OnCallStep[]
}
}
interface OnCallStep {
id: string
stepNumber: number
escalationPolicy: {
id: string
name: string
assignedTo: {
id: string
name: string
}[]
}
}

interface Service {
id: string
Expand All @@ -56,22 +34,20 @@ interface Service {
// with policy information mapped in the following structure:
// {id: 'svc id', name: 'svc name', policyName: 'policy name', policySteps: [0,1,2]}
//
function services(onCallSteps: OnCallStep[] = []): Service[] {
function services(onCallSteps: OnCallServiceAssignment[] = []): Service[] {
const svcs: { [index: string]: Service } = {}
;(onCallSteps || []).forEach((s) =>
(s.escalationPolicy.assignedTo || []).forEach((svc) => {
if (!svcs[svc.id]) {
svcs[svc.id] = {
id: svc.id,
name: svc.name,
policyName: s.escalationPolicy.name,
policySteps: [s.stepNumber],
}
} else {
svcs[svc.id].policySteps.push(s.stepNumber)
;(onCallSteps || []).forEach((s) => {
if (!svcs[s.serviceID]) {
svcs[s.serviceID] = {
id: s.serviceID,
name: s.serviceName,
policyName: s.escalationPolicyName,
policySteps: [s.stepNumber],
}
}),
)
} else {
svcs[s.serviceID].policySteps.push(s.stepNumber)
}
})

let result = values(svcs)
result = sortBy(result, 'name')
Expand All @@ -84,7 +60,7 @@ export default function UserOnCallAssignmentList(props: {
currentUser?: boolean
}): JSX.Element {
const userID = props.userID
const [{ data, error }] = useQuery({
const [{ data, error }] = useQuery<{ user: User }>({
query,
variables: { id: userID },
})
Expand All @@ -96,7 +72,7 @@ export default function UserOnCallAssignmentList(props: {
return <ObjectNotFound />
}

const user = (data as QueryResult).user
const user = data.user

return (
<Card>
Expand All @@ -111,7 +87,7 @@ export default function UserOnCallAssignmentList(props: {
? 'You are not currently on-call.'
: `${user.name} is not currently on-call.`
}
items={services(user.onCallSteps).map((svc) => ({
items={services(user.onCallOverview.serviceAssignments).map((svc) => ({
title: svc.name,
url: '/services/' + svc.id,
subText: `${svc.policyName}: ${svc.policySteps
Expand Down

0 comments on commit ff2ccc5

Please sign in to comment.