@atlaskit/profilecard 16.12.1 → 17.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/cjs/client/ProfileCardClient.js +4 -4
- package/dist/cjs/client/TeamCentralCardClient.js +106 -59
- package/dist/cjs/client/TeamProfileCardClient.js +13 -12
- package/dist/cjs/client/UserProfileCardClient.js +25 -2
- package/dist/cjs/client/errorUtils.js +25 -0
- package/dist/cjs/components/Error/ErrorMessage.js +40 -77
- package/dist/cjs/components/Team/TeamLoadingState.js +1 -1
- package/dist/cjs/components/Team/TeamProfileCard.js +4 -4
- package/dist/cjs/components/Team/TeamProfileCardTrigger.js +3 -3
- package/dist/cjs/components/User/OverflowProfileCardButtons.js +44 -10
- package/dist/cjs/components/User/ProfileCard.js +195 -362
- package/dist/cjs/components/User/ProfileCardDetails.js +142 -0
- package/dist/cjs/components/User/ProfileCardResourced.js +25 -20
- package/dist/cjs/components/User/ProfileCardTrigger.js +35 -7
- package/dist/cjs/components/User/ReportingLinesDetails.js +13 -13
- package/dist/cjs/components/User/UserLoadingState.js +14 -2
- package/dist/cjs/util/analytics.js +31 -16
- package/dist/cjs/version.json +1 -1
- package/dist/es2019/client/ProfileCardClient.js +4 -4
- package/dist/es2019/client/TeamCentralCardClient.js +101 -59
- package/dist/es2019/client/TeamProfileCardClient.js +3 -9
- package/dist/es2019/client/UserProfileCardClient.js +23 -2
- package/dist/es2019/client/errorUtils.js +17 -0
- package/dist/es2019/components/Error/ErrorMessage.js +38 -42
- package/dist/es2019/components/Team/TeamLoadingState.js +2 -2
- package/dist/es2019/components/Team/TeamProfileCard.js +5 -5
- package/dist/es2019/components/Team/TeamProfileCardTrigger.js +4 -4
- package/dist/es2019/components/User/OverflowProfileCardButtons.js +30 -4
- package/dist/es2019/components/User/ProfileCard.js +161 -292
- package/dist/es2019/components/User/ProfileCardDetails.js +118 -0
- package/dist/es2019/components/User/ProfileCardResourced.js +21 -21
- package/dist/es2019/components/User/ProfileCardTrigger.js +32 -6
- package/dist/es2019/components/User/ReportingLinesDetails.js +10 -11
- package/dist/es2019/components/User/UserLoadingState.js +10 -2
- package/dist/es2019/util/analytics.js +13 -8
- package/dist/es2019/version.json +1 -1
- package/dist/esm/client/ProfileCardClient.js +4 -4
- package/dist/esm/client/TeamCentralCardClient.js +106 -59
- package/dist/esm/client/TeamProfileCardClient.js +11 -12
- package/dist/esm/client/UserProfileCardClient.js +22 -2
- package/dist/esm/client/errorUtils.js +17 -0
- package/dist/esm/components/Error/ErrorMessage.js +35 -80
- package/dist/esm/components/Team/TeamLoadingState.js +2 -2
- package/dist/esm/components/Team/TeamProfileCard.js +5 -5
- package/dist/esm/components/Team/TeamProfileCardTrigger.js +4 -4
- package/dist/esm/components/User/OverflowProfileCardButtons.js +39 -9
- package/dist/esm/components/User/ProfileCard.js +180 -362
- package/dist/esm/components/User/ProfileCardDetails.js +120 -0
- package/dist/esm/components/User/ProfileCardResourced.js +17 -17
- package/dist/esm/components/User/ProfileCardTrigger.js +33 -7
- package/dist/esm/components/User/ReportingLinesDetails.js +12 -12
- package/dist/esm/components/User/UserLoadingState.js +7 -2
- package/dist/esm/util/analytics.js +21 -12
- package/dist/esm/version.json +1 -1
- package/dist/types/client/ProfileCardClient.d.ts +3 -2
- package/dist/types/client/TeamCentralCardClient.d.ts +2 -0
- package/dist/types/client/TeamProfileCardClient.d.ts +2 -1
- package/dist/types/client/UserProfileCardClient.d.ts +2 -1
- package/dist/types/client/errorUtils.d.ts +6 -0
- package/dist/types/components/Error/ErrorMessage.d.ts +6 -15
- package/dist/types/components/Team/TeamProfileCardTrigger.d.ts +5 -11
- package/dist/types/components/User/OverflowProfileCardButtons.d.ts +4 -3
- package/dist/types/components/User/ProfileCard.d.ts +5 -29
- package/dist/types/components/User/ProfileCardDetails.d.ts +3 -0
- package/dist/types/components/User/ProfileCardResourced.d.ts +7 -3
- package/dist/types/components/User/ProfileCardTrigger.d.ts +3 -40
- package/dist/types/components/User/ReportingLinesDetails.d.ts +2 -4
- package/dist/types/components/User/UserLoadingState.d.ts +5 -1
- package/dist/types/components/User/lazyProfileCard.d.ts +1 -1
- package/dist/types/types.d.ts +12 -10
- package/dist/types/util/analytics.d.ts +22 -13
- package/package.json +9 -9
- package/report.api.md +74 -124
- package/dist/cjs/internal/analytics.js +0 -15
- package/dist/es2019/internal/analytics.js +0 -8
- package/dist/esm/internal/analytics.js +0 -8
- package/dist/types/internal/analytics.d.ts +0 -8
|
@@ -46,6 +46,14 @@ const buildCheckFeatureFlagQuery = (featureKey, context) => ({
|
|
|
46
46
|
}
|
|
47
47
|
});
|
|
48
48
|
|
|
49
|
+
function hasTCWorkspace(config) {
|
|
50
|
+
return config.cloudId ? fetch(`/gateway/api/watermelon/organization/containsAnyWorkspace?cloudId=${config.cloudId}`).then(res => {
|
|
51
|
+
return !res || res && res.ok;
|
|
52
|
+
}) : Promise.resolve(false);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
let isTCReadyPromiseMap = new Map();
|
|
56
|
+
|
|
49
57
|
class TeamCentralCardClient extends CachingClient {
|
|
50
58
|
/**
|
|
51
59
|
* Simple circuit breaker to avoid making unnecessary calls to Team Central on auth failures
|
|
@@ -60,6 +68,22 @@ class TeamCentralCardClient extends CachingClient {
|
|
|
60
68
|
this.options = options;
|
|
61
69
|
this.bypassOnFailure = false;
|
|
62
70
|
this.featureFlagKeys = new Map();
|
|
71
|
+
this.isTCReadyPromise = this.createTcReadyPromise(options);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
createTcReadyPromise(config) {
|
|
75
|
+
if (config.cloudId) {
|
|
76
|
+
let promise = isTCReadyPromiseMap.get(config.cloudId);
|
|
77
|
+
|
|
78
|
+
if (!promise) {
|
|
79
|
+
promise = hasTCWorkspace(config);
|
|
80
|
+
isTCReadyPromiseMap.set(config.cloudId, promise);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return promise;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return Promise.resolve(true);
|
|
63
87
|
}
|
|
64
88
|
|
|
65
89
|
async makeFeatureFlagCheckRequest(featureKey, context) {
|
|
@@ -68,7 +92,7 @@ class TeamCentralCardClient extends CachingClient {
|
|
|
68
92
|
}
|
|
69
93
|
|
|
70
94
|
const query = buildCheckFeatureFlagQuery(featureKey, context);
|
|
71
|
-
const response = await graphqlQuery(this.options.teamCentralUrl
|
|
95
|
+
const response = await graphqlQuery(`${this.options.teamCentralUrl}?operationName=isFeatureKeyEnabled`, query);
|
|
72
96
|
return response.isFeatureEnabled.enabled;
|
|
73
97
|
}
|
|
74
98
|
|
|
@@ -78,83 +102,101 @@ class TeamCentralCardClient extends CachingClient {
|
|
|
78
102
|
}
|
|
79
103
|
|
|
80
104
|
const query = buildReportingLinesQuery(userId);
|
|
81
|
-
const response = await graphqlQuery(this.options.teamCentralUrl
|
|
105
|
+
const response = await graphqlQuery(`${this.options.teamCentralUrl}?operationName=ReportingLines`, query);
|
|
82
106
|
return response.reportingLines;
|
|
83
107
|
}
|
|
84
108
|
|
|
85
109
|
getReportingLines(userId) {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
if (cache) {
|
|
93
|
-
return Promise.resolve(cache);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
if (this.bypassOnFailure) {
|
|
97
|
-
return Promise.resolve({});
|
|
98
|
-
}
|
|
110
|
+
return this.isTCReadyPromise.then(workSpaceExists => {
|
|
111
|
+
if (workSpaceExists) {
|
|
112
|
+
if (!userId) {
|
|
113
|
+
return Promise.reject(new Error('userId missing'));
|
|
114
|
+
}
|
|
99
115
|
|
|
100
|
-
|
|
101
|
-
this.makeRequest(userId).then(data => {
|
|
102
|
-
const enhancedData = {
|
|
103
|
-
managers: this.filterReportingLinesUser(data === null || data === void 0 ? void 0 : data.managers),
|
|
104
|
-
reports: this.filterReportingLinesUser(data === null || data === void 0 ? void 0 : data.reports)
|
|
105
|
-
};
|
|
116
|
+
const cache = this.getCachedProfile(userId);
|
|
106
117
|
|
|
107
|
-
if (
|
|
108
|
-
|
|
118
|
+
if (cache) {
|
|
119
|
+
return Promise.resolve(cache);
|
|
109
120
|
}
|
|
110
121
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
if ((error === null || error === void 0 ? void 0 : error.status) === 401 || (error === null || error === void 0 ? void 0 : error.status) === 403) {
|
|
114
|
-
// Trigger circuit breaker
|
|
115
|
-
this.bypassOnFailure = true;
|
|
122
|
+
if (this.bypassOnFailure) {
|
|
123
|
+
return Promise.resolve({});
|
|
116
124
|
}
|
|
117
|
-
/**
|
|
118
|
-
* Reporting lines aren't part of the critical path of profile card.
|
|
119
|
-
* Just resolve with empty values instead of bubbling up the error.
|
|
120
|
-
*/
|
|
121
125
|
|
|
126
|
+
return new Promise(resolve => {
|
|
127
|
+
this.makeRequest(userId).then(data => {
|
|
128
|
+
const enhancedData = {
|
|
129
|
+
managers: this.filterReportingLinesUser(data === null || data === void 0 ? void 0 : data.managers),
|
|
130
|
+
reports: this.filterReportingLinesUser(data === null || data === void 0 ? void 0 : data.reports)
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
if (this.cache) {
|
|
134
|
+
this.setCachedProfile(userId, enhancedData);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
resolve(enhancedData);
|
|
138
|
+
}).catch(error => {
|
|
139
|
+
if ((error === null || error === void 0 ? void 0 : error.status) === 401 || (error === null || error === void 0 ? void 0 : error.status) === 403) {
|
|
140
|
+
// Trigger circuit breaker
|
|
141
|
+
this.bypassOnFailure = true;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Reporting lines aren't part of the critical path of profile card.
|
|
145
|
+
* Just resolve with empty values instead of bubbling up the error.
|
|
146
|
+
*/
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
resolve({});
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
}
|
|
122
153
|
|
|
123
|
-
|
|
154
|
+
return Promise.resolve({
|
|
155
|
+
managers: [],
|
|
156
|
+
reports: []
|
|
124
157
|
});
|
|
125
|
-
})
|
|
158
|
+
}, () => Promise.resolve({
|
|
159
|
+
managers: [],
|
|
160
|
+
reports: []
|
|
161
|
+
}));
|
|
126
162
|
}
|
|
127
163
|
|
|
128
164
|
getFlagEnabled(featureKey, productIdentifier) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
return Promise.resolve(this.featureFlagKeys.get(featureKey));
|
|
135
|
-
}
|
|
165
|
+
return this.isTCReadyPromise.then(workSpaceExists => {
|
|
166
|
+
if (workSpaceExists) {
|
|
167
|
+
if (!featureKey) {
|
|
168
|
+
return Promise.reject(new Error('featureKey missing'));
|
|
169
|
+
}
|
|
136
170
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
171
|
+
if (this.featureFlagKeys.has(featureKey)) {
|
|
172
|
+
return Promise.resolve(this.featureFlagKeys.get(featureKey));
|
|
173
|
+
}
|
|
140
174
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
value: productIdentifier || 'unset'
|
|
144
|
-
}];
|
|
145
|
-
return new Promise(resolve => {
|
|
146
|
-
this.makeFeatureFlagCheckRequest(featureKey, context).then(enabled => {
|
|
147
|
-
this.featureFlagKeys.set(featureKey, enabled);
|
|
148
|
-
resolve(enabled);
|
|
149
|
-
}).catch(error => {
|
|
150
|
-
if ((error === null || error === void 0 ? void 0 : error.status) === 401 || (error === null || error === void 0 ? void 0 : error.status) === 403) {
|
|
151
|
-
// Trigger circuit breaker
|
|
152
|
-
this.bypassOnFailure = true;
|
|
175
|
+
if (this.bypassOnFailure) {
|
|
176
|
+
return Promise.resolve(false);
|
|
153
177
|
}
|
|
154
178
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
179
|
+
const context = [{
|
|
180
|
+
key: 'productIdentifier',
|
|
181
|
+
value: productIdentifier || 'unset'
|
|
182
|
+
}];
|
|
183
|
+
return new Promise(resolve => {
|
|
184
|
+
this.makeFeatureFlagCheckRequest(featureKey, context).then(enabled => {
|
|
185
|
+
this.featureFlagKeys.set(featureKey, enabled);
|
|
186
|
+
resolve(enabled);
|
|
187
|
+
}).catch(error => {
|
|
188
|
+
if ((error === null || error === void 0 ? void 0 : error.status) === 401 || (error === null || error === void 0 ? void 0 : error.status) === 403) {
|
|
189
|
+
// Trigger circuit breaker
|
|
190
|
+
this.bypassOnFailure = true;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
resolve(false);
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return Promise.resolve(false);
|
|
199
|
+
}, () => Promise.resolve(false));
|
|
158
200
|
}
|
|
159
201
|
|
|
160
202
|
filterReportingLinesUser(users = []) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { teamRequestAnalytics } from '../util/analytics';
|
|
2
2
|
import { getPageTime } from '../util/performance';
|
|
3
3
|
import CachingClient from './CachingClient';
|
|
4
|
+
import { getErrorAttributes } from './errorUtils';
|
|
4
5
|
import { getTeamFromAGG } from './getTeamFromAGG';
|
|
5
6
|
import { graphqlQuery } from './graphqlUtils';
|
|
6
7
|
const QUERY = `query Team($teamId: String!, $organizationId: String) {
|
|
@@ -28,12 +29,6 @@ const buildTeamQuery = (teamId, orgId) => ({
|
|
|
28
29
|
}
|
|
29
30
|
});
|
|
30
31
|
|
|
31
|
-
const IGNORED_ERRORS = ['NotPermitted', 'Gone'];
|
|
32
|
-
|
|
33
|
-
function isRealError(error) {
|
|
34
|
-
return !IGNORED_ERRORS.includes(error.reason);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
32
|
export default class TeamProfileCardClient extends CachingClient {
|
|
38
33
|
constructor(options) {
|
|
39
34
|
super(options);
|
|
@@ -91,11 +86,10 @@ export default class TeamProfileCardClient extends CachingClient {
|
|
|
91
86
|
|
|
92
87
|
resolve(data);
|
|
93
88
|
}).catch(error => {
|
|
94
|
-
if (analytics
|
|
89
|
+
if (analytics) {
|
|
95
90
|
analytics(teamRequestAnalytics('failed', {
|
|
96
91
|
duration: getPageTime() - startTime,
|
|
97
|
-
|
|
98
|
-
errorReason: error.reason,
|
|
92
|
+
...getErrorAttributes(error),
|
|
99
93
|
gateway: shouldUseGateway
|
|
100
94
|
}));
|
|
101
95
|
}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import { userRequestAnalytics } from '../util/analytics';
|
|
2
|
+
import { getPageTime } from '../util/performance';
|
|
1
3
|
import CachingClient from './CachingClient';
|
|
4
|
+
import { getErrorAttributes } from './errorUtils';
|
|
2
5
|
import { graphqlQuery } from './graphqlUtils';
|
|
3
6
|
/**
|
|
4
7
|
* Transform response from GraphQL
|
|
@@ -21,7 +24,6 @@ export const modifyResponse = response => {
|
|
|
21
24
|
return {
|
|
22
25
|
isBot: data.isBot,
|
|
23
26
|
isCurrentUser: data.isCurrentUser,
|
|
24
|
-
isNotMentionable: data.isNotMentionable,
|
|
25
27
|
status: data.status,
|
|
26
28
|
statusModifiedDate: data.statusModifiedDate || undefined,
|
|
27
29
|
avatarUrl: data.avatarUrl || undefined,
|
|
@@ -83,7 +85,7 @@ export default class UserProfileCardClient extends CachingClient {
|
|
|
83
85
|
return modifyResponse(response);
|
|
84
86
|
}
|
|
85
87
|
|
|
86
|
-
getProfile(cloudId, userId) {
|
|
88
|
+
getProfile(cloudId, userId, analytics) {
|
|
87
89
|
if (!userId) {
|
|
88
90
|
return Promise.reject(new Error('userId missing'));
|
|
89
91
|
}
|
|
@@ -96,13 +98,32 @@ export default class UserProfileCardClient extends CachingClient {
|
|
|
96
98
|
}
|
|
97
99
|
|
|
98
100
|
return new Promise((resolve, reject) => {
|
|
101
|
+
const startTime = getPageTime();
|
|
102
|
+
|
|
103
|
+
if (analytics) {
|
|
104
|
+
analytics(userRequestAnalytics('triggered'));
|
|
105
|
+
}
|
|
106
|
+
|
|
99
107
|
this.makeRequest(cloudId, userId).then(data => {
|
|
100
108
|
if (this.cache) {
|
|
101
109
|
this.setCachedProfile(cacheIdentifier, data);
|
|
102
110
|
}
|
|
103
111
|
|
|
112
|
+
if (analytics) {
|
|
113
|
+
analytics(userRequestAnalytics('succeeded', {
|
|
114
|
+
duration: getPageTime() - startTime
|
|
115
|
+
}));
|
|
116
|
+
}
|
|
117
|
+
|
|
104
118
|
resolve(data);
|
|
105
119
|
}).catch(error => {
|
|
120
|
+
if (analytics) {
|
|
121
|
+
analytics(userRequestAnalytics('failed', {
|
|
122
|
+
duration: getPageTime() - startTime,
|
|
123
|
+
...getErrorAttributes(error)
|
|
124
|
+
}));
|
|
125
|
+
}
|
|
126
|
+
|
|
106
127
|
reject(error);
|
|
107
128
|
});
|
|
108
129
|
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const IGNORED_ERRORS = ['NotPermitted', 'Gone'];
|
|
2
|
+
|
|
3
|
+
function isIgnoredError(error) {
|
|
4
|
+
return !!error && IGNORED_ERRORS.includes(error.reason);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const getErrorAttributes = error => {
|
|
8
|
+
var _error$response, _error$response$heade;
|
|
9
|
+
|
|
10
|
+
const traceId = !!error ? (_error$response = error.response) === null || _error$response === void 0 ? void 0 : (_error$response$heade = _error$response.headers) === null || _error$response$heade === void 0 ? void 0 : _error$response$heade.get('atl-traceid') : undefined;
|
|
11
|
+
return {
|
|
12
|
+
errorStatus: error === null || error === void 0 ? void 0 : error.code,
|
|
13
|
+
errorReason: error === null || error === void 0 ? void 0 : error.reason,
|
|
14
|
+
isSLOFailure: !isIgnoredError(error),
|
|
15
|
+
traceId: traceId !== null && traceId !== void 0 ? traceId : undefined
|
|
16
|
+
};
|
|
17
|
+
};
|
|
@@ -1,47 +1,43 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import AkButton from '@atlaskit/button/custom-theme-button';
|
|
1
|
+
import React, { useEffect } from 'react';
|
|
2
|
+
import Button from '@atlaskit/button/standard-button';
|
|
4
3
|
import IconError from '@atlaskit/icon/glyph/cross-circle';
|
|
5
4
|
import { ErrorText, ErrorTitle, ErrorWrapper } from '../../styled/Error';
|
|
6
|
-
|
|
7
|
-
constructor(...args) {
|
|
8
|
-
super(...args);
|
|
5
|
+
import { profileCardRendered } from '../../util/analytics';
|
|
9
6
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
return this.renderDefault();
|
|
7
|
+
const ErrorMessage = props => {
|
|
8
|
+
const errorType = props.errorType || {
|
|
9
|
+
reason: 'default'
|
|
10
|
+
};
|
|
11
|
+
const errorReason = errorType.reason;
|
|
12
|
+
const {
|
|
13
|
+
fireAnalytics,
|
|
14
|
+
reload
|
|
15
|
+
} = props;
|
|
16
|
+
const hasRetry = !!reload;
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
fireAnalytics(profileCardRendered('user', 'error', {
|
|
19
|
+
hasRetry,
|
|
20
|
+
errorType: errorReason
|
|
21
|
+
}));
|
|
22
|
+
}, [errorReason, fireAnalytics, hasRetry]);
|
|
23
|
+
|
|
24
|
+
const errorContent = () => {
|
|
25
|
+
if (errorReason === 'NotFound') {
|
|
26
|
+
return /*#__PURE__*/React.createElement(ErrorTitle, null, "The user is no longer available for the site");
|
|
31
27
|
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
render() {
|
|
35
|
-
return /*#__PURE__*/React.createElement(ErrorWrapper, null, /*#__PURE__*/React.createElement(IconError, {
|
|
36
|
-
label: "icon error",
|
|
37
|
-
size: "xlarge"
|
|
38
|
-
}), this.renderErrorContent(), this.renderRetryButton());
|
|
39
|
-
}
|
|
40
28
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
|
|
29
|
+
return /*#__PURE__*/React.createElement(ErrorTitle, null, "Oops, looks like we\u2019re having issues", /*#__PURE__*/React.createElement("br", null), reload && /*#__PURE__*/React.createElement(ErrorText, null, "Try again and we\u2019ll give it another shot"));
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
return /*#__PURE__*/React.createElement(ErrorWrapper, {
|
|
33
|
+
"data-testid": "profilecard-error"
|
|
34
|
+
}, /*#__PURE__*/React.createElement(IconError, {
|
|
35
|
+
label: "icon error",
|
|
36
|
+
size: "xlarge"
|
|
37
|
+
}), errorContent(), reload && /*#__PURE__*/React.createElement(Button, {
|
|
38
|
+
appearance: "link",
|
|
39
|
+
onClick: reload
|
|
40
|
+
}, "Try again"));
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export default ErrorMessage;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import React, { useEffect } from 'react';
|
|
2
2
|
import Spinner from '@atlaskit/spinner';
|
|
3
3
|
import { CardContent, CardHeader, CardWrapper, LoadingWrapper } from '../../styled/TeamCard';
|
|
4
|
-
import {
|
|
4
|
+
import { profileCardRendered } from '../../util/analytics';
|
|
5
5
|
export default (props => {
|
|
6
6
|
const {
|
|
7
7
|
analytics
|
|
8
8
|
} = props;
|
|
9
9
|
useEffect(() => {
|
|
10
|
-
analytics(duration =>
|
|
10
|
+
analytics(duration => profileCardRendered('team', 'spinner', {
|
|
11
11
|
duration
|
|
12
12
|
}));
|
|
13
13
|
}, [analytics]);
|
|
@@ -13,7 +13,7 @@ import messages from '../../messages';
|
|
|
13
13
|
import { AnimatedKudosButton, KudosBlobAnimation } from '../../styled/Card';
|
|
14
14
|
import { ErrorWrapper, TeamErrorText, TeamErrorTitle } from '../../styled/Error';
|
|
15
15
|
import { ActionButtons, AvatarSection, CardContent, CardHeader, CardWrapper, Description, DescriptionWrapper, MemberCount, MoreButton, TeamName, WrappedButton } from '../../styled/TeamCard';
|
|
16
|
-
import { errorRetryClicked, moreActionsClicked, moreMembersClicked,
|
|
16
|
+
import { actionClicked, errorRetryClicked, moreActionsClicked, moreMembersClicked, profileCardRendered, teamAvatarClicked } from '../../util/analytics';
|
|
17
17
|
import { isBasicClick } from '../../util/click';
|
|
18
18
|
import { ErrorIllustration } from '../Error';
|
|
19
19
|
import TeamLoadingState from './TeamLoadingState';
|
|
@@ -88,7 +88,7 @@ const TeamMembers = ({
|
|
|
88
88
|
|
|
89
89
|
function onActionClick(action, analytics, index) {
|
|
90
90
|
return (event, ...args) => {
|
|
91
|
-
analytics(duration =>
|
|
91
|
+
analytics(duration => actionClicked('team', {
|
|
92
92
|
duration,
|
|
93
93
|
hasHref: !!action.link,
|
|
94
94
|
hasOnClick: !!action.callback,
|
|
@@ -132,7 +132,7 @@ const ExtraActions = ({
|
|
|
132
132
|
const onMoreClick = useCallback(shouldBeOpen => {
|
|
133
133
|
if (shouldBeOpen) {
|
|
134
134
|
// Only fire this event when OPENING the dropdown
|
|
135
|
-
analytics(duration => moreActionsClicked({
|
|
135
|
+
analytics(duration => moreActionsClicked('team', {
|
|
136
136
|
duration,
|
|
137
137
|
numActions: count + 2
|
|
138
138
|
}));
|
|
@@ -209,7 +209,7 @@ const TeamProfilecardContent = ({
|
|
|
209
209
|
analytics(duration => {
|
|
210
210
|
var _team$members;
|
|
211
211
|
|
|
212
|
-
return
|
|
212
|
+
return profileCardRendered('team', 'content', {
|
|
213
213
|
duration,
|
|
214
214
|
numActions: allActions.length,
|
|
215
215
|
memberCount: (_team$members = team.members) === null || _team$members === void 0 ? void 0 : _team$members.length,
|
|
@@ -242,7 +242,7 @@ const ErrorMessage = ({
|
|
|
242
242
|
}) => {
|
|
243
243
|
const hasRetry = !!clientFetchProfile;
|
|
244
244
|
useEffect(() => {
|
|
245
|
-
analytics(duration =>
|
|
245
|
+
analytics(duration => profileCardRendered('team', 'error', {
|
|
246
246
|
duration,
|
|
247
247
|
hasRetry
|
|
248
248
|
}));
|
|
@@ -8,7 +8,7 @@ import Popup from '@atlaskit/popup';
|
|
|
8
8
|
import { layers } from '@atlaskit/theme/constants';
|
|
9
9
|
import filterActions from '../../internal/filterActions';
|
|
10
10
|
import messages from '../../messages';
|
|
11
|
-
import {
|
|
11
|
+
import { cardTriggered, fireEvent, profileCardRendered } from '../../util/analytics';
|
|
12
12
|
import { isBasicClick } from '../../util/click';
|
|
13
13
|
import { DELAY_MS_HIDE, DELAY_MS_SHOW } from '../../util/config';
|
|
14
14
|
import { getPageTime } from '../../util/performance';
|
|
@@ -89,7 +89,7 @@ export class TeamProfileCardTriggerInternal extends React.PureComponent {
|
|
|
89
89
|
this.showProfilecard(0);
|
|
90
90
|
|
|
91
91
|
if (!this.state.visible) {
|
|
92
|
-
this.fireAnalytics(
|
|
92
|
+
this.fireAnalytics(cardTriggered('team', 'click'));
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
});
|
|
@@ -101,7 +101,7 @@ export class TeamProfileCardTriggerInternal extends React.PureComponent {
|
|
|
101
101
|
|
|
102
102
|
if (!this.state.visible) {
|
|
103
103
|
this.openedByHover = true;
|
|
104
|
-
this.fireAnalytics(
|
|
104
|
+
this.fireAnalytics(cardTriggered('team', 'hover'));
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
this.showProfilecard(DELAY_MS_SHOW);
|
|
@@ -197,7 +197,7 @@ export class TeamProfileCardTriggerInternal extends React.PureComponent {
|
|
|
197
197
|
});
|
|
198
198
|
|
|
199
199
|
_defineProperty(this, "onErrorBoundary", () => {
|
|
200
|
-
this.fireAnalytics(
|
|
200
|
+
this.fireAnalytics(profileCardRendered('team', 'errorBoundary', {
|
|
201
201
|
duration: 0
|
|
202
202
|
}));
|
|
203
203
|
this.setState({
|
|
@@ -1,14 +1,40 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/extends";
|
|
2
|
-
import React from 'react';
|
|
2
|
+
import React, { useCallback, useState } from 'react';
|
|
3
3
|
import { useIntl } from 'react-intl-next';
|
|
4
4
|
import Button from '@atlaskit/button/custom-theme-button';
|
|
5
5
|
import DropdownMenu, { DropdownItem, DropdownItemGroup } from '@atlaskit/dropdown-menu';
|
|
6
6
|
import MoreIcon from '@atlaskit/icon/glyph/more';
|
|
7
7
|
import messages from '../../messages';
|
|
8
8
|
import { OverflowActionButtonsWrapper } from '../../styled/Card';
|
|
9
|
+
import { moreActionsClicked } from '../../util/analytics';
|
|
10
|
+
export const ACTION_OVERFLOW_THRESHOLD = 2;
|
|
9
11
|
export const OverflowProfileCardButtons = props => {
|
|
10
12
|
const intl = useIntl();
|
|
11
|
-
|
|
13
|
+
const [, setOpen] = useState(false);
|
|
14
|
+
const {
|
|
15
|
+
actions,
|
|
16
|
+
onItemClick,
|
|
17
|
+
fireAnalyticsWithDuration
|
|
18
|
+
} = props;
|
|
19
|
+
const numActions = actions.length + ACTION_OVERFLOW_THRESHOLD;
|
|
20
|
+
const onOpenChange = useCallback(({
|
|
21
|
+
isOpen: nextOpen
|
|
22
|
+
}) => {
|
|
23
|
+
setOpen(prevOpen => {
|
|
24
|
+
if (nextOpen && !prevOpen) {
|
|
25
|
+
fireAnalyticsWithDuration(duration => moreActionsClicked('user', {
|
|
26
|
+
duration,
|
|
27
|
+
numActions
|
|
28
|
+
}));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return nextOpen;
|
|
32
|
+
});
|
|
33
|
+
}, [numActions, fireAnalyticsWithDuration]);
|
|
34
|
+
return /*#__PURE__*/React.createElement(OverflowActionButtonsWrapper, {
|
|
35
|
+
"data-testid": "profilecard-actions-overflow"
|
|
36
|
+
}, /*#__PURE__*/React.createElement(DropdownMenu, {
|
|
37
|
+
onOpenChange: onOpenChange,
|
|
12
38
|
placement: 'bottom-end',
|
|
13
39
|
trigger: ({
|
|
14
40
|
triggerRef,
|
|
@@ -23,10 +49,10 @@ export const OverflowProfileCardButtons = props => {
|
|
|
23
49
|
label: intl.formatMessage(messages.profileCardMoreIconLabel)
|
|
24
50
|
})
|
|
25
51
|
}))
|
|
26
|
-
}, /*#__PURE__*/React.createElement(DropdownItemGroup, null,
|
|
52
|
+
}, /*#__PURE__*/React.createElement(DropdownItemGroup, null, actions.map((action, index) => /*#__PURE__*/React.createElement(DropdownItem, {
|
|
27
53
|
key: action.id,
|
|
28
54
|
onClick: (event, ...args) => {
|
|
29
|
-
|
|
55
|
+
onItemClick(action, args, event, index);
|
|
30
56
|
},
|
|
31
57
|
href: action.link
|
|
32
58
|
}, action.label)))));
|