Skip to content

Commit 9be6153

Browse files
authored
fix: add eventing to multi-org (#5486)
1 parent cffff92 commit 9be6153

File tree

9 files changed

+309
-89
lines changed

9 files changed

+309
-89
lines changed

src/identity/components/GlobalHeader/AccountDropdown.tsx

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,22 @@ type OrgSummaryItem = OrganizationSummaries[number]
77
import {OrganizationSummaries, UserAccount} from 'src/client/unityRoutes'
88

99
interface Props {
10-
activeOrg: OrgSummaryItem
1110
activeAccount: UserAccount
1211
accountsList: UserAccount[]
12+
activeOrg: OrgSummaryItem
1313
}
1414

15+
// Eventing
16+
import {
17+
HeaderNavEvent,
18+
MainMenuEventPrefix,
19+
multiOrgTag,
20+
TypeAheadEventPrefix,
21+
} from 'src/identity/events/multiOrgEvents'
22+
import {event} from 'src/cloud/utils/reporting'
23+
1524
// Styles
16-
const style = {width: 'auto'}
25+
const accountDropdownStyle = {width: 'auto'}
1726
const menuStyle = {width: '250px'}
1827

1928
// Components
@@ -26,9 +35,9 @@ import {
2635
import {CLOUD_URL} from 'src/shared/constants'
2736

2837
export const AccountDropdown: FC<Props> = ({
29-
activeOrg,
30-
activeAccount,
3138
accountsList,
39+
activeAccount,
40+
activeOrg,
3241
}) => {
3342
const selectedAccount = {
3443
id: activeAccount.id.toString(),
@@ -50,23 +59,35 @@ export const AccountDropdown: FC<Props> = ({
5059

5160
// Quartz handles switching accounts by having the user hit this URL.
5261
const switchAccount = (account: TypeAheadMenuItem) => {
62+
event(HeaderNavEvent.AccountSwitch, multiOrgTag, {
63+
newAccountID: account.id,
64+
newAccountName: account.name,
65+
})
5366
window.location.href = `${CLOUD_URL}/accounts/${account.id}`
5467
}
5568

69+
const sendDropdownClickEvent = () => {
70+
event(HeaderNavEvent.AccountDropdownClick, multiOrgTag)
71+
}
72+
5673
return (
57-
<GlobalHeaderDropdown
58-
dropdownMenuStyle={menuStyle}
59-
mainMenuHeaderIcon={IconFont.Switch_New}
60-
mainMenuHeaderText="Switch Account"
61-
mainMenuOptions={accountMainMenu}
62-
mainMenuTestID="globalheader--account-dropdown-main"
63-
style={style}
64-
testID="globalheader--account-dropdown"
65-
typeAheadInputPlaceholder="Search Accounts"
66-
typeAheadMenuOptions={accountsList}
67-
typeAheadOnSelectOption={switchAccount}
68-
typeAheadSelectedOption={selectedAccount}
69-
typeAheadTestID="globalheader--account-dropdown-typeahead"
70-
/>
74+
<div onClick={sendDropdownClickEvent}>
75+
<GlobalHeaderDropdown
76+
dropdownMenuStyle={menuStyle}
77+
mainMenuEventPrefix={MainMenuEventPrefix.SwitchAccount}
78+
mainMenuHeaderIcon={IconFont.Switch_New}
79+
mainMenuHeaderText="Switch Account"
80+
mainMenuOptions={accountMainMenu}
81+
mainMenuTestID="globalheader--account-dropdown-main"
82+
style={accountDropdownStyle}
83+
testID="globalheader--account-dropdown"
84+
typeAheadEventPrefix={TypeAheadEventPrefix.HeaderNavSearchAccount}
85+
typeAheadInputPlaceholder="Search Accounts"
86+
typeAheadMenuOptions={accountsList}
87+
typeAheadOnSelectOption={switchAccount}
88+
typeAheadSelectedOption={selectedAccount}
89+
typeAheadTestID="globalheader--account-dropdown-typeahead"
90+
/>
91+
</div>
7192
)
7293
}

src/identity/components/GlobalHeader/GlobalHeaderDropdown/GlobalHeaderTypeAheadMenu.tsx

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,30 @@
1+
// Libraries
12
import React, {ChangeEvent} from 'react'
23
import {Dropdown, Input} from '@influxdata/clockface'
34
import {FixedSizeList as List} from 'react-window'
45
import classnames from 'classnames'
56
import {TypeAheadMenuItem} from 'src/identity/components/GlobalHeader/GlobalHeaderDropdown'
67

8+
// Eventing
9+
import {
10+
multiOrgTag,
11+
TypeAheadEventPrefix,
12+
} from 'src/identity/events/multiOrgEvents'
13+
import {event} from 'src/cloud/utils/reporting'
14+
715
type Props = {
816
defaultSelectedItem?: TypeAheadMenuItem
9-
style?: React.CSSProperties
10-
typeAheadPlaceHolder: string
11-
typeAheadMenuOptions: TypeAheadMenuItem[]
1217
onSelectOption: (item: TypeAheadMenuItem) => void
18+
style?: React.CSSProperties
1319
testID: string
20+
typeAheadEventPrefix: TypeAheadEventPrefix
21+
typeAheadMenuOptions: TypeAheadMenuItem[]
22+
typeAheadPlaceHolder: string
1423
}
1524

1625
type State = {
17-
searchTerm: string
1826
queryResults: TypeAheadMenuItem[]
27+
searchTerm: string
1928
selectedItem: TypeAheadMenuItem
2029
}
2130

@@ -25,15 +34,15 @@ export class GlobalHeaderTypeAheadMenu extends React.Component<Props, State> {
2534
constructor(props: Props) {
2635
super(props)
2736
this.state = {
28-
searchTerm: '',
2937
queryResults: this.props.typeAheadMenuOptions,
38+
searchTerm: '',
3039
selectedItem: this.props.defaultSelectedItem,
3140
}
3241
}
3342

34-
private selectAllTextInInput = (event?: ChangeEvent<HTMLInputElement>) => {
35-
if (event) {
36-
event.target.select()
43+
private selectAllTextInInput = (evt?: ChangeEvent<HTMLInputElement>) => {
44+
if (evt) {
45+
evt.target.select()
3746
}
3847
}
3948

@@ -57,8 +66,8 @@ export class GlobalHeaderTypeAheadMenu extends React.Component<Props, State> {
5766
}
5867
}
5968

60-
private handleInputChange = (event: ChangeEvent<HTMLInputElement>) => {
61-
const filterString = event?.target?.value
69+
private handleInputChange = (evt: ChangeEvent<HTMLInputElement>) => {
70+
const filterString = evt?.target?.value
6271
this.applyFilter(filterString)
6372
}
6473

@@ -85,6 +94,19 @@ export class GlobalHeaderTypeAheadMenu extends React.Component<Props, State> {
8594
}
8695
}
8796

97+
private sendTypeAheadSearchEvent = (evt: ChangeEvent<HTMLInputElement>) => {
98+
const {typeAheadEventPrefix} = this.props
99+
100+
// No event should be sent if the input field is empty, or just contains whitespace.
101+
102+
if (
103+
typeof evt?.target?.value === 'string' &&
104+
evt.target.value.trim().length
105+
) {
106+
event(`${typeAheadEventPrefix}.searched`, multiOrgTag)
107+
}
108+
}
109+
88110
private calculateDropdownHeight = (numberOfItems: number) =>
89111
Math.min(numberOfItems * this.listItemHeight, this.maxDropdownHeight)
90112

@@ -100,6 +122,7 @@ export class GlobalHeaderTypeAheadMenu extends React.Component<Props, State> {
100122
testID={this.props.testID}
101123
onClear={this.clearFilter}
102124
onFocus={this.selectAllTextInInput}
125+
onBlur={this.sendTypeAheadSearchEvent}
103126
className="global-header--typeahead-input"
104127
/>
105128
)

src/identity/components/GlobalHeader/GlobalHeaderDropdown/index.tsx

Lines changed: 55 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ import './GlobalHeaderDropdown.scss'
2020
// Types
2121
import GlobalHeaderTypeAheadMenu from 'src/identity/components/GlobalHeader/GlobalHeaderDropdown/GlobalHeaderTypeAheadMenu'
2222

23+
// Eventing
24+
import {
25+
MainMenuEventPrefix,
26+
multiOrgTag,
27+
TypeAheadEventPrefix,
28+
} from 'src/identity/events/multiOrgEvents'
29+
import {event} from 'src/cloud/utils/reporting'
30+
2331
export interface MainMenuItem {
2432
name: string
2533
iconFont: string
@@ -34,20 +42,22 @@ export interface TypeAheadMenuItem {
3442
export interface Props extends StandardFunctionProps {
3543
defaultButtonText?: string
3644
defaultTestID?: string
37-
dropdownButtonSize?: ComponentSize
3845
dropdownButtonIcon?: IconFont
46+
dropdownButtonSize?: ComponentSize
3947
dropdownMenuStyle?: React.CSSProperties
4048
dropdownMenuTheme?: DropdownMenuTheme
41-
mainMenuHeaderText?: string
49+
mainMenuEventPrefix?: MainMenuEventPrefix
4250
mainMenuHeaderIcon?: IconFont
51+
mainMenuHeaderText?: string
4352
mainMenuOptions: MainMenuItem[]
4453
mainMenuTestID?: string
4554
onlyRenderSubmenu?: boolean
4655
testID?: string
47-
typeAheadSelectedOption?: TypeAheadMenuItem
48-
typeAheadMenuOptions: TypeAheadMenuItem[]
56+
typeAheadEventPrefix: TypeAheadEventPrefix
4957
typeAheadInputPlaceholder?: string
58+
typeAheadMenuOptions: TypeAheadMenuItem[]
5059
typeAheadOnSelectOption?: (item: TypeAheadMenuItem | null) => void
60+
typeAheadSelectedOption?: TypeAheadMenuItem
5161
typeAheadTestID?: string
5262
}
5363

@@ -80,46 +90,63 @@ export class GlobalHeaderDropdown extends React.Component<Props, State> {
8090
const {
8191
defaultButtonText,
8292
defaultTestID,
83-
dropdownButtonSize,
8493
dropdownButtonIcon,
94+
dropdownButtonSize,
8595
} = this.props
8696
const {selectedItem} = this.state
8797
return (
8898
<Dropdown.Button
8999
active={active}
100+
className="global-header--dropdown-button"
90101
onClick={onClick}
91102
size={dropdownButtonSize}
92-
trailingIcon={dropdownButtonIcon || IconFont.DoubleCaretVertical}
93-
className="global-header--dropdown-button"
94103
testID={defaultTestID}
104+
trailingIcon={dropdownButtonIcon || IconFont.DoubleCaretVertical}
95105
>
96106
{selectedItem?.name || defaultButtonText}
97107
</Dropdown.Button>
98108
)
99109
}
100110

111+
private sendMainMenuEvent = (menuItem: string) => () => {
112+
const {mainMenuEventPrefix} = this.props
113+
event(`${mainMenuEventPrefix}${menuItem}.clicked`, multiOrgTag)
114+
}
115+
101116
private toggleShowTypeAheadMenu = () => {
117+
const {mainMenuEventPrefix} = this.props
102118
const {showTypeAheadMenu} = this.state
119+
// 'Clicked the switch button' event only emitted when opening the typeahead.
120+
if (!showTypeAheadMenu) {
121+
event(`${mainMenuEventPrefix}Switch.clicked`, multiOrgTag)
122+
}
103123
this.setState({showTypeAheadMenu: !showTypeAheadMenu})
104124
}
105125

106126
private renderMainMenuOptions = () => {
107127
const {mainMenuOptions} = this.props
108128
return (
109129
<div>
110-
{mainMenuOptions.map(value => {
111-
const iconEl = <Icon glyph={value.iconFont} className="button-icon" />
112-
const textEl = <span>{value.name}</span>
130+
{mainMenuOptions.map(menuItem => {
131+
const iconEl = (
132+
<Icon glyph={menuItem.iconFont} className="button-icon" />
133+
)
134+
const textEl = <span>{menuItem.name}</span>
113135
return (
114-
<Dropdown.HrefItem
115-
key={value.name}
116-
href={value.href}
117-
className="global-header--align-center"
118-
testID={`${this.props.mainMenuTestID}-${value.name}`}
136+
<div
137+
onClick={this.sendMainMenuEvent(menuItem.name)}
138+
key={`eventWrapper.${menuItem.name}`}
119139
>
120-
{iconEl}
121-
{textEl}
122-
</Dropdown.HrefItem>
140+
<Dropdown.HrefItem
141+
className="global-header--align-center"
142+
key={menuItem.name}
143+
href={menuItem.href}
144+
testID={`${this.props.mainMenuTestID}-${menuItem.name}`}
145+
>
146+
{iconEl}
147+
{textEl}
148+
</Dropdown.HrefItem>
149+
</div>
123150
)
124151
})}
125152
</div>
@@ -130,29 +157,31 @@ export class GlobalHeaderDropdown extends React.Component<Props, State> {
130157
const {typeAheadMenuOptions} = this.props
131158
const {selectedItem} = this.state
132159
const {
160+
dropdownMenuStyle,
161+
typeAheadEventPrefix,
133162
typeAheadInputPlaceholder,
134163
typeAheadOnSelectOption,
135-
dropdownMenuStyle,
136164
} = this.props
137165
return (
138166
<GlobalHeaderTypeAheadMenu
139-
typeAheadPlaceHolder={typeAheadInputPlaceholder}
140-
typeAheadMenuOptions={typeAheadMenuOptions}
167+
defaultSelectedItem={selectedItem}
141168
onSelectOption={typeAheadOnSelectOption}
142169
style={dropdownMenuStyle}
143-
defaultSelectedItem={selectedItem}
144170
testID={this.props.typeAheadTestID}
171+
typeAheadEventPrefix={typeAheadEventPrefix}
172+
typeAheadMenuOptions={typeAheadMenuOptions}
173+
typeAheadPlaceHolder={typeAheadInputPlaceholder}
145174
/>
146175
)
147176
}
148177

149178
private renderMenu = () => {
150179
const {
151-
mainMenuHeaderText,
152-
dropdownMenuTheme = DropdownMenuTheme.None,
153180
dropdownMenuStyle,
154-
typeAheadMenuOptions,
181+
dropdownMenuTheme = DropdownMenuTheme.None,
182+
mainMenuHeaderText,
155183
onlyRenderSubmenu = false,
184+
typeAheadMenuOptions,
156185
} = this.props
157186
const {showTypeAheadMenu} = this.state
158187

@@ -210,8 +239,8 @@ export class GlobalHeaderDropdown extends React.Component<Props, State> {
210239
return (
211240
<Dropdown
212241
{...dropdownProps}
213-
disableAutoFocus
214242
button={this.dropdownButton}
243+
disableAutoFocus
215244
menu={this.renderMenu}
216245
testID={this.props.testID}
217246
/>

0 commit comments

Comments
 (0)