@boomerang-io/carbon-addons-boomerang-react 4.6.14-beta.0 → 4.6.14-beta.10

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.
@@ -62,7 +62,7 @@ const MenuAriaLabelRecord = {
62
62
  const headerButtonClassNames = "cds--btn--icon-only cds--header__action cds--btn cds--btn--primary cds--btn--icon-only cds--btn cds--btn--primary";
63
63
  const instanceCheckMarkContainerClass = "instance-checkmark-style-container";
64
64
  function Header(props) {
65
- const { analyticsHelpers, productName, baseEnvUrl, baseServicesUrl, carbonTheme = "g10", className, createJoinTeamTrigger, history, isLaunchpad = false, isLoadingTeamSwitcher, isSuccessTeamSwitcher, setIsSuccessTeamSwitcher, navLinks, platform, prefixName = "", refetchUser, refetchNavigation, rightPanel, skipToContentProps, templateMeteringEvent, trackEvent, triggerEvent, user, userTeams, userTeamsAssets, } = props;
65
+ const { analyticsHelpers, productName, baseEnvUrl, baseServicesUrl, carbonTheme = "g10", className, createJoinTeamTrigger, enableTeamSwitcher = true, history, isLaunchpad = false, isLoadingTeamSwitcher, isSuccessTeamSwitcher, setIsSuccessTeamSwitcher, navLinks, platform, prefixName = "", refetchUser, refetchNavigation, rightPanel, skipToContentProps, templateMeteringEvent, trackEvent, triggerEvent, user, userTeams, userTeamsAssets, } = props;
66
66
  const hasUserTeams = Boolean(userTeams);
67
67
  const userTeamsUrl = servicesConfig.serviceUrl.getUserTeamsServices({ baseServicesUrl });
68
68
  const teamsQuery = reactQuery.useQuery({
@@ -70,6 +70,7 @@ function Header(props) {
70
70
  queryFn: servicesConfig.resolver.query(userTeamsUrl, null),
71
71
  enabled: !hasUserTeams && Boolean(baseServicesUrl),
72
72
  });
73
+ const showTeamSwitcher = enableTeamSwitcher && Boolean(user);
73
74
  return (React__default.default.createElement(React__default.default.Fragment, null,
74
75
  React__default.default.createElement(react.Theme, { theme: carbonTheme },
75
76
  React__default.default.createElement(react.Header, { "aria-label": "App navigation header", className: className },
@@ -80,7 +81,7 @@ function Header(props) {
80
81
  ? navLinks.map((link) => (React__default.default.createElement(react.HeaderMenuItem, { "aria-label": `Link for ${link.name}`, "data-testid": "header-menu-link", href: link.url, isCurrentPage: window?.location?.href && link.url ? window.location.href.startsWith(link.url) : false, key: link.name, target: link.isExternal ? "_blank" : undefined, rel: link.isExternal ? "noopener noreferrer" : undefined }, link.name)))
81
82
  : null),
82
83
  React__default.default.createElement(react.HeaderGlobalBar, null,
83
- React__default.default.createElement(HeaderTeamSwitcher.default, { analyticsHelpers: analyticsHelpers, baseServicesUrl: baseServicesUrl, createJoinTeamTrigger: createJoinTeamTrigger, history: history, isLaunchpad: isLaunchpad, isLoadingTeamSwitcher: isLoadingTeamSwitcher, isSuccessTeamSwitcher: isSuccessTeamSwitcher, setIsSuccessTeamSwitcher: setIsSuccessTeamSwitcher, menuAriaLabelRecord: MenuAriaLabelRecord.TeamSwitcher, menuButtonId: MenuButtonId.TeamSwitcher, menuListId: MenuListId.TeamSwitcher, navigationPlatform: platform, refetchUser: refetchUser, refetchNavigation: refetchNavigation, teamsQuery: teamsQuery, trackEvent: trackEvent, user: user, userTeams: userTeams }),
84
+ showTeamSwitcher ? (React__default.default.createElement(HeaderTeamSwitcher.default, { analyticsHelpers: analyticsHelpers, baseServicesUrl: baseServicesUrl, createJoinTeamTrigger: createJoinTeamTrigger, history: history, isLaunchpad: isLaunchpad, isLoadingTeamSwitcher: isLoadingTeamSwitcher, isSuccessTeamSwitcher: isSuccessTeamSwitcher, setIsSuccessTeamSwitcher: setIsSuccessTeamSwitcher, menuAriaLabelRecord: MenuAriaLabelRecord.TeamSwitcher, menuButtonId: MenuButtonId.TeamSwitcher, menuListId: MenuListId.TeamSwitcher, navigationPlatform: platform, refetchUser: refetchUser, refetchNavigation: refetchNavigation, teamsQuery: teamsQuery, trackEvent: trackEvent, user: user, userTeams: userTeams })) : null,
84
85
  props?.instanceSwitcherEnabled && (React__default.default.createElement(InstanceSwitcherMenu, { enabled: Boolean(props.instanceSwitcherEnabled), menuItems: platform?.instances })),
85
86
  React__default.default.createElement(RequestsMenu, { baseEnvUrl: baseEnvUrl, enabled: Boolean(props.requestSummary), summary: props.requestSummary }),
86
87
  React__default.default.createElement(NotificationsMenu, { baseEnvUrl: baseEnvUrl, baseServicesUrl: baseServicesUrl, enabled: Boolean(props.enableNotifications), countEnabled: Boolean(props.enableNotificationsCount) }),
@@ -11,6 +11,7 @@ var HeaderMenu = require('./HeaderMenu.js');
11
11
  var servicesConfig = require('../../config/servicesConfig.js');
12
12
  var settings = require('../../internal/settings.js');
13
13
  var UserType = require('../../constants/UserType.js');
14
+ var TeamTypes = require('../../constants/TeamTypes.js');
14
15
 
15
16
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
16
17
 
@@ -26,6 +27,9 @@ const headerDropdownMenuContainerClassname = `${settings.prefix}--header-dropdow
26
27
  const headerDropdownMenuLoadingClassname = `${settings.prefix}--header-dropdown-menu-loading`;
27
28
  const headerDropdownMenuSuccessClassname = `${settings.prefix}--header-dropdown-menu-success`;
28
29
  const headerDropdownMenuClassname = `${settings.prefix}--header-dropdown-menu`;
30
+ const headerDropdownMenuContentClassname = `${settings.prefix}--header-dropdown-menu-content`;
31
+ const headerDropdownMenuContentTextClassname = `${settings.prefix}--header-dropdown-menu-content-text`;
32
+ const headerDropdownMenuContentIconClassname = `${settings.prefix}--header-dropdown-menu-content-icon`;
29
33
  const headerDropdownMenuListClassname = `${settings.prefix}--bmrg-header-drop-down`;
30
34
  const headerDropdownMenuItemContainerClassname = `${settings.prefix}--header-dropdown-menu-item-container`;
31
35
  const headerDropdownMenuItemClassname = `${settings.prefix}--header-dropdown-menu-item`;
@@ -94,6 +98,12 @@ function HeaderTeamSwitcher({ analyticsHelpers, baseServicesUrl, createJoinTeamT
94
98
  await mutateUserProfile({ baseServicesUrl, body });
95
99
  }
96
100
  };
101
+ const handleNoTeamsToSelect = async () => {
102
+ const body = {
103
+ teamInstanceSwitcherDefault: null,
104
+ };
105
+ await mutateUserProfile({ baseServicesUrl, body });
106
+ };
97
107
  if (userHasTeams) {
98
108
  if (!userTeamInstanceSwitcherDefault) {
99
109
  if (userHasPersonalTeam) {
@@ -125,6 +135,21 @@ function HeaderTeamSwitcher({ analyticsHelpers, baseServicesUrl, createJoinTeamT
125
135
  const newSelectedTeam = allTeams.find((team) => team.id === userTeamInstanceSwitcherDefault);
126
136
  handleSelectTeam({ team: newSelectedTeam });
127
137
  }
138
+ // if teams data loaded but there are no teams
139
+ }
140
+ else if (Boolean(userTeamInstanceSwitcherDefault) &&
141
+ ((hasUserTeams &&
142
+ userTeams?.data?.accountTeams?.length === 0 &&
143
+ userTeams?.data?.standardTeams?.length === 0 &&
144
+ userTeams?.data?.personalTeam?.length === 0) ||
145
+ (!hasUserTeams &&
146
+ teamsQuery?.data?.accountTeams?.length === 0 &&
147
+ teamsQuery?.data?.standardTeams?.length === 0 &&
148
+ teamsQuery?.data?.personalTeam?.length === 0))) {
149
+ handleNoTeamsToSelect();
150
+ }
151
+ else if (userTeamInstanceSwitcherDefault === null) {
152
+ setSelectedTeam(null);
128
153
  }
129
154
  }, [
130
155
  baseServicesUrl,
@@ -202,44 +227,72 @@ function HeaderTeamSwitcher({ analyticsHelpers, baseServicesUrl, createJoinTeamT
202
227
  standardTeams = teamsQuery?.data?.standardTeams ?? [];
203
228
  personalTeam = teamsQuery?.data?.personalTeam ?? [];
204
229
  }
205
- let sortedAccountTeamsWithNamesToDisplay = [];
206
- let sortedStandardTeamsWithNamesToDisplay = [];
230
+ let newPersonalTeam = personalTeam.length > 0
231
+ ? personalTeam.map((personalTeam) => ({
232
+ ...personalTeam,
233
+ type: TeamTypes.TEAM_TYPES.PERSONAL,
234
+ nameToDisplay: personalTeam.displayName ? personalTeam.displayName : personalTeam.name,
235
+ }))
236
+ : [];
237
+ let newAccountTeams = [];
238
+ let newStandardTeams = [];
207
239
  if (accountTeams?.length > 0) {
208
- const newAccountTeams = accountTeams.map((team) => {
240
+ newAccountTeams = accountTeams.map((team) => {
209
241
  let newProjectTeams = [];
210
242
  if (team.projectTeams && team.projectTeams.length > 0) {
211
- newProjectTeams = team.projectTeams?.map((team) => ({
212
- ...team,
213
- nameToDisplay: team.displayName ? team.displayName : team.name,
214
- }));
243
+ newProjectTeams = team.projectTeams?.map((projectTeam) => {
244
+ return {
245
+ ...projectTeam,
246
+ nameToDisplay: projectTeam.displayName ? projectTeam.displayName : projectTeam.name,
247
+ };
248
+ });
215
249
  }
216
250
  return {
217
251
  ...team,
218
252
  nameToDisplay: team.displayName ? team.displayName : team.name,
253
+ type: TeamTypes.TEAM_TYPES.ACCOUNT,
219
254
  projectTeams: sortBy__default.default(newProjectTeams, ["nameToDisplay"]),
220
255
  };
221
256
  });
222
- sortedAccountTeamsWithNamesToDisplay = sortBy__default.default(newAccountTeams, ["nameToDisplay"]);
223
257
  }
224
258
  if (standardTeams?.length > 0) {
225
- const newStandardTeams = standardTeams.map((team) => {
259
+ newStandardTeams = standardTeams.map((team) => {
226
260
  return {
227
261
  ...team,
262
+ type: TeamTypes.TEAM_TYPES.STANDARD,
228
263
  nameToDisplay: team.displayName ? team.displayName : team.name,
229
264
  };
230
265
  });
231
- sortedStandardTeamsWithNamesToDisplay = sortBy__default.default(newStandardTeams, ["nameToDisplay"]);
232
266
  }
233
- let selectedTeamName = selectedTeam?.displayName ? selectedTeam.displayName : selectedTeam?.name;
234
- if (selectedTeamName && selectedTeamName.length > 65) {
235
- selectedTeamName = selectedTeamName.slice(0, 65) + "...";
267
+ let allTeams = newPersonalTeam.concat(newAccountTeams, newStandardTeams);
268
+ const order = { [TeamTypes.TEAM_TYPES.PERSONAL]: 1, [TeamTypes.TEAM_TYPES.ACCOUNT]: 2, [TeamTypes.TEAM_TYPES.STANDARD]: 3 };
269
+ allTeams = sortBy__default.default(allTeams, [(team) => order[team.type], "nameToDisplay"]);
270
+ if (selectedTeam) {
271
+ const selectedTeamIndex = allTeams.findIndex((team, index) => {
272
+ if (team.id === selectedTeam.id) {
273
+ return true;
274
+ }
275
+ else if (Array.isArray(team.projectTeams) && team.projectTeams?.length > 0) {
276
+ return team.projectTeams.some((projectTeam) => projectTeam.id === selectedTeam.id);
277
+ }
278
+ return false;
279
+ });
280
+ const [removedTeam] = allTeams.splice(selectedTeamIndex, 1);
281
+ allTeams.unshift(removedTeam);
236
282
  }
283
+ let selectedTeamName = selectedTeam?.displayName
284
+ ? selectedTeam.displayName
285
+ : selectedTeam?.name
286
+ ? selectedTeam?.name
287
+ : "No team selected";
237
288
  const isPartnerUser = Boolean(user?.type === UserType.USER_PLATFORM_ROLE.Partner);
238
289
  return (React__default.default.createElement("div", { className: headerDropdownMenuContainerClassname },
239
290
  isLoadingTeamSwitcher ? (React__default.default.createElement("div", { className: headerDropdownMenuLoadingClassname },
240
291
  React__default.default.createElement(react.InlineLoading, null))) : isSuccessTeamSwitcher ? (React__default.default.createElement("div", { className: headerDropdownMenuSuccessClassname },
241
292
  React__default.default.createElement(icons.CheckmarkFilled, null))) : null,
242
- React__default.default.createElement(react.HeaderMenu, { id: "header-team-switcher-menu", "aria-label": menuAriaLabelRecord, className: headerDropdownMenuClassname, menuLinkName: selectedTeamName ? selectedTeamName : "No team selected", onClick: handleHeaderMenuClick, "data-testid": "header-team-switcher-menu" },
293
+ React__default.default.createElement(react.HeaderMenu, { id: "header-team-switcher-menu", "aria-label": menuAriaLabelRecord, className: headerDropdownMenuClassname, renderMenuContent: () => (React__default.default.createElement("div", { className: headerDropdownMenuContentClassname },
294
+ React__default.default.createElement("p", { title: selectedTeamName, className: headerDropdownMenuContentTextClassname }, selectedTeamName),
295
+ React__default.default.createElement(icons.ChevronDown, { className: headerDropdownMenuContentIconClassname }))), onClick: handleHeaderMenuClick, "data-testid": "header-team-switcher-menu" },
243
296
  React__default.default.createElement(HeaderMenu.default, { "aria-labelledby": menuButtonId, className: headerDropdownMenuListClassname, id: menuListId },
244
297
  !isPartnerUser && (React__default.default.createElement(react.HeaderMenuItem, { id: "header-team-switcher-create-join-team-button", className: headerTeamSwitcherCreateTeamButtonContainerClassname, onClick: handleCreateJoinTeamClick,
245
298
  // eslint-disable-next-line no-script-url
@@ -247,28 +300,13 @@ function HeaderTeamSwitcher({ analyticsHelpers, baseServicesUrl, createJoinTeamT
247
300
  React__default.default.createElement("div", { className: headerTeamSwitcherCreateTeamButtonClassname },
248
301
  React__default.default.createElement("span", { className: headerTeamSwitcherCreateTeamButtonTextClassname }, createTeamButtonText),
249
302
  React__default.default.createElement(icons.AddAlt, { className: headerTeamSwitcherCreateTeamButtonIconClassname })))),
250
- personalTeam.length > 0
251
- ? personalTeam.map((team) => {
252
- const teamName = team.displayName ? team.displayName : team.name;
253
- const isTeamSelected = team.id === selectedTeam?.id;
254
- return (React__default.default.createElement("div", { key: team.id, id: `${team.id}-personal-menu-item-id` },
255
- React__default.default.createElement(react.HeaderMenuItem, { key: team.id, id: `${team.id}-personal-menu-item`, "aria-selected": isTeamSelected, className: headerDropdownMenuItemContainerClassname, onClick: () => {
256
- handleTeamClick({ team, type: "personal" });
257
- },
258
- // eslint-disable-next-line no-script-url
259
- href: "javascript:void(0)", "data-testid": "header-team-switcher-menu-item" },
260
- React__default.default.createElement("div", { className: headerDropdownMenuItemClassname },
261
- React__default.default.createElement("span", { title: teamName, className: headerDropdownMenuItemTextClassname }, teamName),
262
- isTeamSelected ? React__default.default.createElement(icons.CheckmarkFilled, { className: headerDropdownMenuItemIconClassname }) : null))));
263
- })
264
- : null,
265
- accountTeams.length > 0
266
- ? sortedAccountTeamsWithNamesToDisplay.map((team) => {
303
+ allTeams.map((team) => {
304
+ const isTeamSelected = team.id === selectedTeam?.id;
305
+ if (team.type === TeamTypes.TEAM_TYPES.ACCOUNT) {
267
306
  const isSubmenuOpen = team.id === openAccountSubmenuId;
268
307
  const isProjectTeamSelected = team.projectTeams &&
269
308
  team.projectTeams.length > 0 &&
270
309
  team.projectTeams.some((team) => team.id === selectedTeam?.id);
271
- const isTeamSelected = team.id === selectedTeam?.id;
272
310
  const isMenuSelected = isTeamSelected || isProjectTeamSelected;
273
311
  return (React__default.default.createElement("div", { key: team.id, id: `${team.id}-account-menu` },
274
312
  React__default.default.createElement(react.HeaderMenuItem, { "aria-expanded": isSubmenuOpen, "aria-selected": isMenuSelected, className: headerDropdownMenuItemAccountContainerClassname, onClick: (e) => handleOpenAccountSubmenu({ e, id: team.id }),
@@ -277,7 +315,7 @@ function HeaderTeamSwitcher({ analyticsHelpers, baseServicesUrl, createJoinTeamT
277
315
  React__default.default.createElement("div", { className: headerDropdownMenuItemAccountClassname },
278
316
  React__default.default.createElement("div", { className: headerDropdownMenuItemTextIconClassname },
279
317
  React__default.default.createElement("span", { title: team.nameToDisplay, className: headerDropdownMenuItemTextClassname }, team.nameToDisplay),
280
- isMenuSelected ? (React__default.default.createElement(icons.CheckmarkFilled, { className: headerDropdownMenuItemIconClassname })) : null),
318
+ isMenuSelected ? React__default.default.createElement(icons.CheckmarkFilled, { className: headerDropdownMenuItemIconClassname }) : null),
281
319
  React__default.default.createElement("div", { className: headerDropdownMenuItemAccountIconsClassname },
282
320
  React__default.default.createElement(icons.GroupAccount, { className: headerDropdownMenuItemAccountGroupIconClassname }),
283
321
  React__default.default.createElement(icons.ChevronDown, { className: headerDropdownMenuItemAccountChevronIconClassname })))),
@@ -289,7 +327,7 @@ function HeaderTeamSwitcher({ analyticsHelpers, baseServicesUrl, createJoinTeamT
289
327
  href: "javascript:void(0)" },
290
328
  React__default.default.createElement("div", { className: headerDropdownMenuItemClassname, style: { paddingLeft: "1rem" } },
291
329
  React__default.default.createElement("span", { title: team.nameToDisplay, className: headerDropdownMenuItemTextClassname }, "Account Page"),
292
- isTeamSelected ? (React__default.default.createElement(icons.CheckmarkFilled, { className: headerDropdownMenuItemIconClassname })) : null)),
330
+ isTeamSelected ? React__default.default.createElement(icons.CheckmarkFilled, { className: headerDropdownMenuItemIconClassname }) : null)),
293
331
  team.projectTeams && team.projectTeams.length > 0
294
332
  ? team.projectTeams.map((team) => {
295
333
  const isTeamSelected = team.id === selectedTeam?.id;
@@ -304,22 +342,19 @@ function HeaderTeamSwitcher({ analyticsHelpers, baseServicesUrl, createJoinTeamT
304
342
  isTeamSelected ? (React__default.default.createElement(icons.CheckmarkFilled, { className: headerDropdownMenuItemIconClassname })) : null))));
305
343
  })
306
344
  : null)));
307
- })
308
- : null,
309
- standardTeams.length > 0
310
- ? sortedStandardTeamsWithNamesToDisplay.map((team) => {
311
- const isTeamSelected = team.id === selectedTeam?.id;
312
- return (React__default.default.createElement("div", { key: team.id, id: `${team.id}-standard-menu-item` },
345
+ }
346
+ else {
347
+ return (React__default.default.createElement("div", { key: team.id, id: `${team.id}-${team.type}-menu-item` },
313
348
  React__default.default.createElement(react.HeaderMenuItem, { "aria-selected": isTeamSelected, className: headerDropdownMenuItemContainerClassname, onClick: () => {
314
- handleTeamClick({ team, type: "standard" });
349
+ handleTeamClick({ team, type: team.type ?? "" });
315
350
  }, "data-testid": "header-team-switcher-menu-item",
316
351
  // eslint-disable-next-line no-script-url
317
352
  href: "javascript:void(0)" },
318
353
  React__default.default.createElement("div", { className: headerDropdownMenuItemClassname },
319
354
  React__default.default.createElement("span", { title: team.nameToDisplay, className: headerDropdownMenuItemTextClassname }, team.nameToDisplay),
320
355
  isTeamSelected ? React__default.default.createElement(icons.CheckmarkFilled, { className: headerDropdownMenuItemIconClassname }) : null))));
321
- })
322
- : null))));
356
+ }
357
+ })))));
323
358
  }
324
359
  return null;
325
360
  }
@@ -34,12 +34,13 @@ function determineIfConfigIsDifferent(teams, initialTeams) {
34
34
  }
35
35
  return isConfigDifferent;
36
36
  }
37
- function ProfileSettings({ baseServicesUrl, src, userName, isOpen, closeModal }) {
37
+ function ProfileSettings({ baseServicesUrl, refetchUser, refetchUserTeams, refetchNavigation, src, userName, isOpen, closeModal, }) {
38
38
  const queryClient = reactQuery.useQueryClient();
39
39
  const [initialTeams, setInitialTeams] = React.useState([]);
40
40
  const [teams, setTeams] = React.useState([]);
41
41
  const userUrl = servicesConfig.serviceUrl.getLaunchpadUser({ baseServicesUrl });
42
42
  const profileUrl = servicesConfig.serviceUrl.resourceUserProfile({ baseServicesUrl });
43
+ const userTeamsUrl = servicesConfig.serviceUrl.getUserTeamsServices({ baseServicesUrl });
43
44
  const { data: user, isLoading: userIsLoading, error: userError, } = reactQuery.useQuery({
44
45
  queryKey: userUrl,
45
46
  queryFn: servicesConfig.resolver.query(userUrl),
@@ -48,6 +49,22 @@ function ProfileSettings({ baseServicesUrl, src, userName, isOpen, closeModal })
48
49
  onSuccess: () => {
49
50
  queryClient.invalidateQueries(userUrl);
50
51
  queryClient.invalidateQueries(profileUrl);
52
+ queryClient.invalidateQueries(userTeamsUrl);
53
+ if (refetchUser) {
54
+ setTimeout(() => {
55
+ refetchUser();
56
+ }, 1000);
57
+ }
58
+ if (refetchUserTeams) {
59
+ setTimeout(() => {
60
+ refetchUserTeams();
61
+ }, 1000);
62
+ }
63
+ if (refetchNavigation) {
64
+ setTimeout(() => {
65
+ refetchNavigation();
66
+ }, 1000);
67
+ }
51
68
  },
52
69
  });
53
70
  // Only disable when we have a user and we know that there aren' any lower level groups to manage
@@ -63,6 +80,7 @@ function ProfileSettings({ baseServicesUrl, src, userName, isOpen, closeModal })
63
80
  }
64
81
  async function handleSubmit() {
65
82
  const body = {
83
+ teamInstanceSwitcherDefault: null,
66
84
  lowerLevelGroups: teams,
67
85
  };
68
86
  try {
@@ -104,9 +122,9 @@ function ProfileSettings({ baseServicesUrl, src, userName, isOpen, closeModal })
104
122
  return (React__default.default.createElement(react.ComposedModal, { "aria-label": "Profile Settings", className: `${settings.prefix}--bmrg-profile-settings-container ${settings.prefix}--bmrg-header-modal`, open: isOpen, onClose: handleClose, preventCloseOnClickOutside: true },
105
123
  React__default.default.createElement(react.ModalHeader, { closeModal: handleClose, title: `User profile - ${userName}` }),
106
124
  React__default.default.createElement(react.ModalBody, { style: { maxHeight: "31.5rem" } },
107
- React__default.default.createElement("p", { className: `${settings.prefix}--bmrg-profile-settings__title` }, "More user profile settings will be here eventually, but for now you can choose which Teams are shown in your sidebar in Launchpad."),
108
- React__default.default.createElement("h2", { className: `${settings.prefix}--bmrg-profile-settings__subtitle` }, "Teams visible in Launchpad sidebar"),
109
- React__default.default.createElement("p", { className: `${settings.prefix}--bmrg-profile-settings__description` }, "Choose Teams to show or hide in your Launchpad sidebar and Catalog (useful for sensitive demos). You will not be able to access or view unchecked Teams from the sidebar, and cannot add items to them from Catalog."),
125
+ React__default.default.createElement("p", { className: `${settings.prefix}--bmrg-profile-settings__title` }, "More user profile settings will be here eventually, but for now you can choose which Teams are shown in your team switcher in Launchpad."),
126
+ React__default.default.createElement("h2", { className: `${settings.prefix}--bmrg-profile-settings__subtitle` }, "Teams visible in Launchpad team switcher"),
127
+ React__default.default.createElement("p", { className: `${settings.prefix}--bmrg-profile-settings__description` }, "Choose Teams to show or hide in your Launchpad team switcher and Catalog (useful for sensitive demos). You will not be able to access or view unchecked Teams from the team switcher, and cannot add items to them from Catalog."),
110
128
  userIsLoading ? (React__default.default.createElement(react.StructuredListSkeleton, null)) : userError ? (React__default.default.createElement(ErrorMessage.default, { style: { color: "#F2F4F8", padding: "1rem" } })) : teams?.length > 0 ? (React__default.default.createElement(react.StructuredListWrapper, { className: `${settings.prefix}--bmrg-profile-settings-list` },
111
129
  React__default.default.createElement(react.StructuredListHead, null,
112
130
  React__default.default.createElement(react.StructuredListRow, { head: true },
@@ -26,11 +26,11 @@ IBM Confidential
26
26
  694970X, 69497O0
27
27
  © Copyright IBM Corp. 2022, 2024
28
28
  */
29
- function UIShell({ analyticsHelpers, baseEnvUrl, carbonTheme = "g10", config, createJoinTeamTrigger, history, isLaunchpad = false, isLoadingTeamSwitcher, isSuccessTeamSwitcher, setIsSuccessTeamSwitcher, leftPanel, platformName, productName, profileMenuItems = [], supportMenuItems = [], renderPrivacyRedirect = true, renderPrivacyStatement = true, rightPanel, handleShowTutorial, refetchUser, refetchNavigation, skipToContentProps, templateMeteringEvent, trackEvent, triggerEvent, tutorialScreenToShow, user, userTeams, userTeamsAssets, enableIcaMacs, }) {
29
+ function UIShell({ analyticsHelpers, baseEnvUrl, carbonTheme = "g10", config, createJoinTeamTrigger, enableTeamSwitcher = true, history, isLaunchpad = false, isLoadingTeamSwitcher, isSuccessTeamSwitcher, setIsSuccessTeamSwitcher, leftPanel, platformName, productName, profileMenuItems = [], supportMenuItems = [], renderPrivacyRedirect = true, renderPrivacyStatement = true, rightPanel, handleShowTutorial, refetchUser, refetchUserTeams, refetchNavigation, skipToContentProps, templateMeteringEvent, trackEvent, triggerEvent, tutorialScreenToShow, user, userTeams, userTeamsAssets, enableIcaMacs, }) {
30
30
  // Support base header .e.g for an error state
31
31
  if (!config) {
32
32
  return (React__default.default.createElement(reactQuery.QueryClientProvider, { client: servicesConfig.queryClient },
33
- React__default.default.createElement(Header.default, { baseEnvUrl: baseEnvUrl ?? "", baseServicesUrl: "", carbonTheme: carbonTheme, enableAppSwitcher: false, enableNotifications: false, enableNotificationsCount: false, productName: productName || platformName || "", user: user })));
33
+ React__default.default.createElement(Header.default, { baseEnvUrl: baseEnvUrl ?? "", baseServicesUrl: "", carbonTheme: carbonTheme, enableAppSwitcher: false, enableNotifications: false, enableNotificationsCount: false, enableTeamSwitcher: enableTeamSwitcher, productName: productName || platformName || "", user: user })));
34
34
  }
35
35
  const { features, navigation, platform, platformMessage } = config;
36
36
  const names = getProductAndPlatformNames({ productName, platformName, platform });
@@ -71,8 +71,8 @@ function UIShell({ analyticsHelpers, baseEnvUrl, carbonTheme = "g10", config, cr
71
71
  */
72
72
  const isPrivacyStatementDisabled = renderPrivacyStatement === false || features?.["consent.enabled"] === false;
73
73
  return (React__default.default.createElement(reactQuery.QueryClientProvider, { client: servicesConfig.queryClient },
74
- React__default.default.createElement(Header.default, { analyticsHelpers: analyticsHelpers, baseEnvUrl: platform.baseEnvUrl, baseServicesUrl: platform.baseServicesUrl, carbonTheme: carbonTheme, createJoinTeamTrigger: createJoinTeamTrigger, enableAppSwitcher: isAppSwitcherEnabled, instanceSwitcherEnabled: instanceSwitcherEnabled, enableNotifications: isNotificationsEnabled, enableNotificationsCount: isNotificationsCountEnabled, leftPanel: leftPanel, navLinks: navigation, platform: platform, platformMessage: platformMessage, prefixName: names.platformName, productName: names.productName, rightPanel: rightPanel, requestSummary: user?.requestSummary, skipToContentProps: skipToContentProps, templateMeteringEvent: templateMeteringEvent, triggerEvent: triggerEvent, profileMenuItems: [
75
- isUserEnabled && (React__default.default.createElement(ProfileSettings.ProfileSettingsMenuItem, { key: "profile-settings", baseServicesUrl: platform.baseServicesUrl, src: `${platform.baseServicesUrl}/users/image/${user?.email}`, userName: user?.displayName ?? user?.name })),
74
+ React__default.default.createElement(Header.default, { analyticsHelpers: analyticsHelpers, baseEnvUrl: platform.baseEnvUrl, baseServicesUrl: platform.baseServicesUrl, carbonTheme: carbonTheme, createJoinTeamTrigger: createJoinTeamTrigger, enableAppSwitcher: isAppSwitcherEnabled, instanceSwitcherEnabled: instanceSwitcherEnabled, enableNotifications: isNotificationsEnabled, enableNotificationsCount: isNotificationsCountEnabled, enableTeamSwitcher: enableTeamSwitcher, leftPanel: leftPanel, navLinks: navigation, platform: platform, platformMessage: platformMessage, prefixName: names.platformName, productName: names.productName, rightPanel: rightPanel, requestSummary: user?.requestSummary, skipToContentProps: skipToContentProps, templateMeteringEvent: templateMeteringEvent, triggerEvent: triggerEvent, profileMenuItems: [
75
+ isUserEnabled && (React__default.default.createElement(ProfileSettings.ProfileSettingsMenuItem, { key: "profile-settings", baseServicesUrl: platform.baseServicesUrl, src: `${platform.baseServicesUrl}/users/image/${user?.email}`, userName: user?.displayName ?? user?.name, refetchUser: refetchUser, refetchUserTeams: refetchUserTeams, refetchNavigation: refetchNavigation })),
76
76
  isSendMailEnabled && (React__default.default.createElement(HeaderMenuItem.default, { key: "email-preferences", href: `${platform.baseEnvUrl}/launchpad/email-preferences`, icon: React__default.default.createElement(icons.Email, null), kind: "internal", text: "Email Preferences", type: "link" })),
77
77
  !isPrivacyStatementDisabled && (React__default.default.createElement(PrivacyStatement.PrivacyStatementMenuItem, { key: "privacy-statement", baseServicesUrl: platform.baseServicesUrl, platformEmail: platform?.platformEmail })),
78
78
  ...profileMenuItems,
@@ -0,0 +1,15 @@
1
+ 'use strict';
2
+
3
+ /*
4
+ IBM Confidential
5
+ 694970X, 69497O0
6
+ © Copyright IBM Corp. 2022, 2024
7
+ */
8
+ const TEAM_TYPES = {
9
+ ACCOUNT: "account",
10
+ PERSONAL: "personal",
11
+ PROJECT: "project",
12
+ STANDARD: "standard",
13
+ };
14
+
15
+ exports.TEAM_TYPES = TEAM_TYPES;
@@ -54,7 +54,7 @@ const MenuAriaLabelRecord = {
54
54
  const headerButtonClassNames = "cds--btn--icon-only cds--header__action cds--btn cds--btn--primary cds--btn--icon-only cds--btn cds--btn--primary";
55
55
  const instanceCheckMarkContainerClass = "instance-checkmark-style-container";
56
56
  function Header(props) {
57
- const { analyticsHelpers, productName, baseEnvUrl, baseServicesUrl, carbonTheme = "g10", className, createJoinTeamTrigger, history, isLaunchpad = false, isLoadingTeamSwitcher, isSuccessTeamSwitcher, setIsSuccessTeamSwitcher, navLinks, platform, prefixName = "", refetchUser, refetchNavigation, rightPanel, skipToContentProps, templateMeteringEvent, trackEvent, triggerEvent, user, userTeams, userTeamsAssets, } = props;
57
+ const { analyticsHelpers, productName, baseEnvUrl, baseServicesUrl, carbonTheme = "g10", className, createJoinTeamTrigger, enableTeamSwitcher = true, history, isLaunchpad = false, isLoadingTeamSwitcher, isSuccessTeamSwitcher, setIsSuccessTeamSwitcher, navLinks, platform, prefixName = "", refetchUser, refetchNavigation, rightPanel, skipToContentProps, templateMeteringEvent, trackEvent, triggerEvent, user, userTeams, userTeamsAssets, } = props;
58
58
  const hasUserTeams = Boolean(userTeams);
59
59
  const userTeamsUrl = serviceUrl.getUserTeamsServices({ baseServicesUrl });
60
60
  const teamsQuery = useQuery({
@@ -62,6 +62,7 @@ function Header(props) {
62
62
  queryFn: resolver.query(userTeamsUrl, null),
63
63
  enabled: !hasUserTeams && Boolean(baseServicesUrl),
64
64
  });
65
+ const showTeamSwitcher = enableTeamSwitcher && Boolean(user);
65
66
  return (React.createElement(React.Fragment, null,
66
67
  React.createElement(Theme, { theme: carbonTheme },
67
68
  React.createElement(Header$1, { "aria-label": "App navigation header", className: className },
@@ -72,7 +73,7 @@ function Header(props) {
72
73
  ? navLinks.map((link) => (React.createElement(HeaderMenuItem, { "aria-label": `Link for ${link.name}`, "data-testid": "header-menu-link", href: link.url, isCurrentPage: window?.location?.href && link.url ? window.location.href.startsWith(link.url) : false, key: link.name, target: link.isExternal ? "_blank" : undefined, rel: link.isExternal ? "noopener noreferrer" : undefined }, link.name)))
73
74
  : null),
74
75
  React.createElement(HeaderGlobalBar, null,
75
- React.createElement(HeaderTeamSwitcher, { analyticsHelpers: analyticsHelpers, baseServicesUrl: baseServicesUrl, createJoinTeamTrigger: createJoinTeamTrigger, history: history, isLaunchpad: isLaunchpad, isLoadingTeamSwitcher: isLoadingTeamSwitcher, isSuccessTeamSwitcher: isSuccessTeamSwitcher, setIsSuccessTeamSwitcher: setIsSuccessTeamSwitcher, menuAriaLabelRecord: MenuAriaLabelRecord.TeamSwitcher, menuButtonId: MenuButtonId.TeamSwitcher, menuListId: MenuListId.TeamSwitcher, navigationPlatform: platform, refetchUser: refetchUser, refetchNavigation: refetchNavigation, teamsQuery: teamsQuery, trackEvent: trackEvent, user: user, userTeams: userTeams }),
76
+ showTeamSwitcher ? (React.createElement(HeaderTeamSwitcher, { analyticsHelpers: analyticsHelpers, baseServicesUrl: baseServicesUrl, createJoinTeamTrigger: createJoinTeamTrigger, history: history, isLaunchpad: isLaunchpad, isLoadingTeamSwitcher: isLoadingTeamSwitcher, isSuccessTeamSwitcher: isSuccessTeamSwitcher, setIsSuccessTeamSwitcher: setIsSuccessTeamSwitcher, menuAriaLabelRecord: MenuAriaLabelRecord.TeamSwitcher, menuButtonId: MenuButtonId.TeamSwitcher, menuListId: MenuListId.TeamSwitcher, navigationPlatform: platform, refetchUser: refetchUser, refetchNavigation: refetchNavigation, teamsQuery: teamsQuery, trackEvent: trackEvent, user: user, userTeams: userTeams })) : null,
76
77
  props?.instanceSwitcherEnabled && (React.createElement(InstanceSwitcherMenu, { enabled: Boolean(props.instanceSwitcherEnabled), menuItems: platform?.instances })),
77
78
  React.createElement(RequestsMenu, { baseEnvUrl: baseEnvUrl, enabled: Boolean(props.requestSummary), summary: props.requestSummary }),
78
79
  React.createElement(NotificationsMenu, { baseEnvUrl: baseEnvUrl, baseServicesUrl: baseServicesUrl, enabled: Boolean(props.enableNotifications), countEnabled: Boolean(props.enableNotificationsCount) }),
@@ -1,12 +1,13 @@
1
1
  import React, { useState, useEffect } from 'react';
2
2
  import { useMutation } from 'react-query';
3
3
  import { InlineLoading, HeaderMenu, HeaderMenuItem } from '@carbon/react';
4
- import { CheckmarkFilled, AddAlt, GroupAccount, ChevronDown } from '@carbon/react/icons';
4
+ import { CheckmarkFilled, ChevronDown, AddAlt, GroupAccount } from '@carbon/react/icons';
5
5
  import sortBy from 'lodash.sortby';
6
6
  import HeaderMenu$1 from './HeaderMenu.js';
7
7
  import { resolver } from '../../config/servicesConfig.js';
8
8
  import { prefix } from '../../internal/settings.js';
9
9
  import { USER_PLATFORM_ROLE } from '../../constants/UserType.js';
10
+ import { TEAM_TYPES } from '../../constants/TeamTypes.js';
10
11
 
11
12
  /*
12
13
  IBM Confidential
@@ -17,6 +18,9 @@ const headerDropdownMenuContainerClassname = `${prefix}--header-dropdown-menu-co
17
18
  const headerDropdownMenuLoadingClassname = `${prefix}--header-dropdown-menu-loading`;
18
19
  const headerDropdownMenuSuccessClassname = `${prefix}--header-dropdown-menu-success`;
19
20
  const headerDropdownMenuClassname = `${prefix}--header-dropdown-menu`;
21
+ const headerDropdownMenuContentClassname = `${prefix}--header-dropdown-menu-content`;
22
+ const headerDropdownMenuContentTextClassname = `${prefix}--header-dropdown-menu-content-text`;
23
+ const headerDropdownMenuContentIconClassname = `${prefix}--header-dropdown-menu-content-icon`;
20
24
  const headerDropdownMenuListClassname = `${prefix}--bmrg-header-drop-down`;
21
25
  const headerDropdownMenuItemContainerClassname = `${prefix}--header-dropdown-menu-item-container`;
22
26
  const headerDropdownMenuItemClassname = `${prefix}--header-dropdown-menu-item`;
@@ -85,6 +89,12 @@ function HeaderTeamSwitcher({ analyticsHelpers, baseServicesUrl, createJoinTeamT
85
89
  await mutateUserProfile({ baseServicesUrl, body });
86
90
  }
87
91
  };
92
+ const handleNoTeamsToSelect = async () => {
93
+ const body = {
94
+ teamInstanceSwitcherDefault: null,
95
+ };
96
+ await mutateUserProfile({ baseServicesUrl, body });
97
+ };
88
98
  if (userHasTeams) {
89
99
  if (!userTeamInstanceSwitcherDefault) {
90
100
  if (userHasPersonalTeam) {
@@ -116,6 +126,21 @@ function HeaderTeamSwitcher({ analyticsHelpers, baseServicesUrl, createJoinTeamT
116
126
  const newSelectedTeam = allTeams.find((team) => team.id === userTeamInstanceSwitcherDefault);
117
127
  handleSelectTeam({ team: newSelectedTeam });
118
128
  }
129
+ // if teams data loaded but there are no teams
130
+ }
131
+ else if (Boolean(userTeamInstanceSwitcherDefault) &&
132
+ ((hasUserTeams &&
133
+ userTeams?.data?.accountTeams?.length === 0 &&
134
+ userTeams?.data?.standardTeams?.length === 0 &&
135
+ userTeams?.data?.personalTeam?.length === 0) ||
136
+ (!hasUserTeams &&
137
+ teamsQuery?.data?.accountTeams?.length === 0 &&
138
+ teamsQuery?.data?.standardTeams?.length === 0 &&
139
+ teamsQuery?.data?.personalTeam?.length === 0))) {
140
+ handleNoTeamsToSelect();
141
+ }
142
+ else if (userTeamInstanceSwitcherDefault === null) {
143
+ setSelectedTeam(null);
119
144
  }
120
145
  }, [
121
146
  baseServicesUrl,
@@ -193,44 +218,72 @@ function HeaderTeamSwitcher({ analyticsHelpers, baseServicesUrl, createJoinTeamT
193
218
  standardTeams = teamsQuery?.data?.standardTeams ?? [];
194
219
  personalTeam = teamsQuery?.data?.personalTeam ?? [];
195
220
  }
196
- let sortedAccountTeamsWithNamesToDisplay = [];
197
- let sortedStandardTeamsWithNamesToDisplay = [];
221
+ let newPersonalTeam = personalTeam.length > 0
222
+ ? personalTeam.map((personalTeam) => ({
223
+ ...personalTeam,
224
+ type: TEAM_TYPES.PERSONAL,
225
+ nameToDisplay: personalTeam.displayName ? personalTeam.displayName : personalTeam.name,
226
+ }))
227
+ : [];
228
+ let newAccountTeams = [];
229
+ let newStandardTeams = [];
198
230
  if (accountTeams?.length > 0) {
199
- const newAccountTeams = accountTeams.map((team) => {
231
+ newAccountTeams = accountTeams.map((team) => {
200
232
  let newProjectTeams = [];
201
233
  if (team.projectTeams && team.projectTeams.length > 0) {
202
- newProjectTeams = team.projectTeams?.map((team) => ({
203
- ...team,
204
- nameToDisplay: team.displayName ? team.displayName : team.name,
205
- }));
234
+ newProjectTeams = team.projectTeams?.map((projectTeam) => {
235
+ return {
236
+ ...projectTeam,
237
+ nameToDisplay: projectTeam.displayName ? projectTeam.displayName : projectTeam.name,
238
+ };
239
+ });
206
240
  }
207
241
  return {
208
242
  ...team,
209
243
  nameToDisplay: team.displayName ? team.displayName : team.name,
244
+ type: TEAM_TYPES.ACCOUNT,
210
245
  projectTeams: sortBy(newProjectTeams, ["nameToDisplay"]),
211
246
  };
212
247
  });
213
- sortedAccountTeamsWithNamesToDisplay = sortBy(newAccountTeams, ["nameToDisplay"]);
214
248
  }
215
249
  if (standardTeams?.length > 0) {
216
- const newStandardTeams = standardTeams.map((team) => {
250
+ newStandardTeams = standardTeams.map((team) => {
217
251
  return {
218
252
  ...team,
253
+ type: TEAM_TYPES.STANDARD,
219
254
  nameToDisplay: team.displayName ? team.displayName : team.name,
220
255
  };
221
256
  });
222
- sortedStandardTeamsWithNamesToDisplay = sortBy(newStandardTeams, ["nameToDisplay"]);
223
257
  }
224
- let selectedTeamName = selectedTeam?.displayName ? selectedTeam.displayName : selectedTeam?.name;
225
- if (selectedTeamName && selectedTeamName.length > 65) {
226
- selectedTeamName = selectedTeamName.slice(0, 65) + "...";
258
+ let allTeams = newPersonalTeam.concat(newAccountTeams, newStandardTeams);
259
+ const order = { [TEAM_TYPES.PERSONAL]: 1, [TEAM_TYPES.ACCOUNT]: 2, [TEAM_TYPES.STANDARD]: 3 };
260
+ allTeams = sortBy(allTeams, [(team) => order[team.type], "nameToDisplay"]);
261
+ if (selectedTeam) {
262
+ const selectedTeamIndex = allTeams.findIndex((team, index) => {
263
+ if (team.id === selectedTeam.id) {
264
+ return true;
265
+ }
266
+ else if (Array.isArray(team.projectTeams) && team.projectTeams?.length > 0) {
267
+ return team.projectTeams.some((projectTeam) => projectTeam.id === selectedTeam.id);
268
+ }
269
+ return false;
270
+ });
271
+ const [removedTeam] = allTeams.splice(selectedTeamIndex, 1);
272
+ allTeams.unshift(removedTeam);
227
273
  }
274
+ let selectedTeamName = selectedTeam?.displayName
275
+ ? selectedTeam.displayName
276
+ : selectedTeam?.name
277
+ ? selectedTeam?.name
278
+ : "No team selected";
228
279
  const isPartnerUser = Boolean(user?.type === USER_PLATFORM_ROLE.Partner);
229
280
  return (React.createElement("div", { className: headerDropdownMenuContainerClassname },
230
281
  isLoadingTeamSwitcher ? (React.createElement("div", { className: headerDropdownMenuLoadingClassname },
231
282
  React.createElement(InlineLoading, null))) : isSuccessTeamSwitcher ? (React.createElement("div", { className: headerDropdownMenuSuccessClassname },
232
283
  React.createElement(CheckmarkFilled, null))) : null,
233
- React.createElement(HeaderMenu, { id: "header-team-switcher-menu", "aria-label": menuAriaLabelRecord, className: headerDropdownMenuClassname, menuLinkName: selectedTeamName ? selectedTeamName : "No team selected", onClick: handleHeaderMenuClick, "data-testid": "header-team-switcher-menu" },
284
+ React.createElement(HeaderMenu, { id: "header-team-switcher-menu", "aria-label": menuAriaLabelRecord, className: headerDropdownMenuClassname, renderMenuContent: () => (React.createElement("div", { className: headerDropdownMenuContentClassname },
285
+ React.createElement("p", { title: selectedTeamName, className: headerDropdownMenuContentTextClassname }, selectedTeamName),
286
+ React.createElement(ChevronDown, { className: headerDropdownMenuContentIconClassname }))), onClick: handleHeaderMenuClick, "data-testid": "header-team-switcher-menu" },
234
287
  React.createElement(HeaderMenu$1, { "aria-labelledby": menuButtonId, className: headerDropdownMenuListClassname, id: menuListId },
235
288
  !isPartnerUser && (React.createElement(HeaderMenuItem, { id: "header-team-switcher-create-join-team-button", className: headerTeamSwitcherCreateTeamButtonContainerClassname, onClick: handleCreateJoinTeamClick,
236
289
  // eslint-disable-next-line no-script-url
@@ -238,28 +291,13 @@ function HeaderTeamSwitcher({ analyticsHelpers, baseServicesUrl, createJoinTeamT
238
291
  React.createElement("div", { className: headerTeamSwitcherCreateTeamButtonClassname },
239
292
  React.createElement("span", { className: headerTeamSwitcherCreateTeamButtonTextClassname }, createTeamButtonText),
240
293
  React.createElement(AddAlt, { className: headerTeamSwitcherCreateTeamButtonIconClassname })))),
241
- personalTeam.length > 0
242
- ? personalTeam.map((team) => {
243
- const teamName = team.displayName ? team.displayName : team.name;
244
- const isTeamSelected = team.id === selectedTeam?.id;
245
- return (React.createElement("div", { key: team.id, id: `${team.id}-personal-menu-item-id` },
246
- React.createElement(HeaderMenuItem, { key: team.id, id: `${team.id}-personal-menu-item`, "aria-selected": isTeamSelected, className: headerDropdownMenuItemContainerClassname, onClick: () => {
247
- handleTeamClick({ team, type: "personal" });
248
- },
249
- // eslint-disable-next-line no-script-url
250
- href: "javascript:void(0)", "data-testid": "header-team-switcher-menu-item" },
251
- React.createElement("div", { className: headerDropdownMenuItemClassname },
252
- React.createElement("span", { title: teamName, className: headerDropdownMenuItemTextClassname }, teamName),
253
- isTeamSelected ? React.createElement(CheckmarkFilled, { className: headerDropdownMenuItemIconClassname }) : null))));
254
- })
255
- : null,
256
- accountTeams.length > 0
257
- ? sortedAccountTeamsWithNamesToDisplay.map((team) => {
294
+ allTeams.map((team) => {
295
+ const isTeamSelected = team.id === selectedTeam?.id;
296
+ if (team.type === TEAM_TYPES.ACCOUNT) {
258
297
  const isSubmenuOpen = team.id === openAccountSubmenuId;
259
298
  const isProjectTeamSelected = team.projectTeams &&
260
299
  team.projectTeams.length > 0 &&
261
300
  team.projectTeams.some((team) => team.id === selectedTeam?.id);
262
- const isTeamSelected = team.id === selectedTeam?.id;
263
301
  const isMenuSelected = isTeamSelected || isProjectTeamSelected;
264
302
  return (React.createElement("div", { key: team.id, id: `${team.id}-account-menu` },
265
303
  React.createElement(HeaderMenuItem, { "aria-expanded": isSubmenuOpen, "aria-selected": isMenuSelected, className: headerDropdownMenuItemAccountContainerClassname, onClick: (e) => handleOpenAccountSubmenu({ e, id: team.id }),
@@ -268,7 +306,7 @@ function HeaderTeamSwitcher({ analyticsHelpers, baseServicesUrl, createJoinTeamT
268
306
  React.createElement("div", { className: headerDropdownMenuItemAccountClassname },
269
307
  React.createElement("div", { className: headerDropdownMenuItemTextIconClassname },
270
308
  React.createElement("span", { title: team.nameToDisplay, className: headerDropdownMenuItemTextClassname }, team.nameToDisplay),
271
- isMenuSelected ? (React.createElement(CheckmarkFilled, { className: headerDropdownMenuItemIconClassname })) : null),
309
+ isMenuSelected ? React.createElement(CheckmarkFilled, { className: headerDropdownMenuItemIconClassname }) : null),
272
310
  React.createElement("div", { className: headerDropdownMenuItemAccountIconsClassname },
273
311
  React.createElement(GroupAccount, { className: headerDropdownMenuItemAccountGroupIconClassname }),
274
312
  React.createElement(ChevronDown, { className: headerDropdownMenuItemAccountChevronIconClassname })))),
@@ -280,7 +318,7 @@ function HeaderTeamSwitcher({ analyticsHelpers, baseServicesUrl, createJoinTeamT
280
318
  href: "javascript:void(0)" },
281
319
  React.createElement("div", { className: headerDropdownMenuItemClassname, style: { paddingLeft: "1rem" } },
282
320
  React.createElement("span", { title: team.nameToDisplay, className: headerDropdownMenuItemTextClassname }, "Account Page"),
283
- isTeamSelected ? (React.createElement(CheckmarkFilled, { className: headerDropdownMenuItemIconClassname })) : null)),
321
+ isTeamSelected ? React.createElement(CheckmarkFilled, { className: headerDropdownMenuItemIconClassname }) : null)),
284
322
  team.projectTeams && team.projectTeams.length > 0
285
323
  ? team.projectTeams.map((team) => {
286
324
  const isTeamSelected = team.id === selectedTeam?.id;
@@ -295,22 +333,19 @@ function HeaderTeamSwitcher({ analyticsHelpers, baseServicesUrl, createJoinTeamT
295
333
  isTeamSelected ? (React.createElement(CheckmarkFilled, { className: headerDropdownMenuItemIconClassname })) : null))));
296
334
  })
297
335
  : null)));
298
- })
299
- : null,
300
- standardTeams.length > 0
301
- ? sortedStandardTeamsWithNamesToDisplay.map((team) => {
302
- const isTeamSelected = team.id === selectedTeam?.id;
303
- return (React.createElement("div", { key: team.id, id: `${team.id}-standard-menu-item` },
336
+ }
337
+ else {
338
+ return (React.createElement("div", { key: team.id, id: `${team.id}-${team.type}-menu-item` },
304
339
  React.createElement(HeaderMenuItem, { "aria-selected": isTeamSelected, className: headerDropdownMenuItemContainerClassname, onClick: () => {
305
- handleTeamClick({ team, type: "standard" });
340
+ handleTeamClick({ team, type: team.type ?? "" });
306
341
  }, "data-testid": "header-team-switcher-menu-item",
307
342
  // eslint-disable-next-line no-script-url
308
343
  href: "javascript:void(0)" },
309
344
  React.createElement("div", { className: headerDropdownMenuItemClassname },
310
345
  React.createElement("span", { title: team.nameToDisplay, className: headerDropdownMenuItemTextClassname }, team.nameToDisplay),
311
346
  isTeamSelected ? React.createElement(CheckmarkFilled, { className: headerDropdownMenuItemIconClassname }) : null))));
312
- })
313
- : null))));
347
+ }
348
+ })))));
314
349
  }
315
350
  return null;
316
351
  }
@@ -25,12 +25,13 @@ function determineIfConfigIsDifferent(teams, initialTeams) {
25
25
  }
26
26
  return isConfigDifferent;
27
27
  }
28
- function ProfileSettings({ baseServicesUrl, src, userName, isOpen, closeModal }) {
28
+ function ProfileSettings({ baseServicesUrl, refetchUser, refetchUserTeams, refetchNavigation, src, userName, isOpen, closeModal, }) {
29
29
  const queryClient = useQueryClient();
30
30
  const [initialTeams, setInitialTeams] = useState([]);
31
31
  const [teams, setTeams] = useState([]);
32
32
  const userUrl = serviceUrl.getLaunchpadUser({ baseServicesUrl });
33
33
  const profileUrl = serviceUrl.resourceUserProfile({ baseServicesUrl });
34
+ const userTeamsUrl = serviceUrl.getUserTeamsServices({ baseServicesUrl });
34
35
  const { data: user, isLoading: userIsLoading, error: userError, } = useQuery({
35
36
  queryKey: userUrl,
36
37
  queryFn: resolver.query(userUrl),
@@ -39,6 +40,22 @@ function ProfileSettings({ baseServicesUrl, src, userName, isOpen, closeModal })
39
40
  onSuccess: () => {
40
41
  queryClient.invalidateQueries(userUrl);
41
42
  queryClient.invalidateQueries(profileUrl);
43
+ queryClient.invalidateQueries(userTeamsUrl);
44
+ if (refetchUser) {
45
+ setTimeout(() => {
46
+ refetchUser();
47
+ }, 1000);
48
+ }
49
+ if (refetchUserTeams) {
50
+ setTimeout(() => {
51
+ refetchUserTeams();
52
+ }, 1000);
53
+ }
54
+ if (refetchNavigation) {
55
+ setTimeout(() => {
56
+ refetchNavigation();
57
+ }, 1000);
58
+ }
42
59
  },
43
60
  });
44
61
  // Only disable when we have a user and we know that there aren' any lower level groups to manage
@@ -54,6 +71,7 @@ function ProfileSettings({ baseServicesUrl, src, userName, isOpen, closeModal })
54
71
  }
55
72
  async function handleSubmit() {
56
73
  const body = {
74
+ teamInstanceSwitcherDefault: null,
57
75
  lowerLevelGroups: teams,
58
76
  };
59
77
  try {
@@ -95,9 +113,9 @@ function ProfileSettings({ baseServicesUrl, src, userName, isOpen, closeModal })
95
113
  return (React.createElement(ComposedModal, { "aria-label": "Profile Settings", className: `${prefix}--bmrg-profile-settings-container ${prefix}--bmrg-header-modal`, open: isOpen, onClose: handleClose, preventCloseOnClickOutside: true },
96
114
  React.createElement(ModalHeader, { closeModal: handleClose, title: `User profile - ${userName}` }),
97
115
  React.createElement(ModalBody, { style: { maxHeight: "31.5rem" } },
98
- React.createElement("p", { className: `${prefix}--bmrg-profile-settings__title` }, "More user profile settings will be here eventually, but for now you can choose which Teams are shown in your sidebar in Launchpad."),
99
- React.createElement("h2", { className: `${prefix}--bmrg-profile-settings__subtitle` }, "Teams visible in Launchpad sidebar"),
100
- React.createElement("p", { className: `${prefix}--bmrg-profile-settings__description` }, "Choose Teams to show or hide in your Launchpad sidebar and Catalog (useful for sensitive demos). You will not be able to access or view unchecked Teams from the sidebar, and cannot add items to them from Catalog."),
116
+ React.createElement("p", { className: `${prefix}--bmrg-profile-settings__title` }, "More user profile settings will be here eventually, but for now you can choose which Teams are shown in your team switcher in Launchpad."),
117
+ React.createElement("h2", { className: `${prefix}--bmrg-profile-settings__subtitle` }, "Teams visible in Launchpad team switcher"),
118
+ React.createElement("p", { className: `${prefix}--bmrg-profile-settings__description` }, "Choose Teams to show or hide in your Launchpad team switcher and Catalog (useful for sensitive demos). You will not be able to access or view unchecked Teams from the team switcher, and cannot add items to them from Catalog."),
101
119
  userIsLoading ? (React.createElement(StructuredListSkeleton, null)) : userError ? (React.createElement(Error, { style: { color: "#F2F4F8", padding: "1rem" } })) : teams?.length > 0 ? (React.createElement(StructuredListWrapper, { className: `${prefix}--bmrg-profile-settings-list` },
102
120
  React.createElement(StructuredListHead, null,
103
121
  React.createElement(StructuredListRow, { head: true },
@@ -18,11 +18,11 @@ IBM Confidential
18
18
  694970X, 69497O0
19
19
  © Copyright IBM Corp. 2022, 2024
20
20
  */
21
- function UIShell({ analyticsHelpers, baseEnvUrl, carbonTheme = "g10", config, createJoinTeamTrigger, history, isLaunchpad = false, isLoadingTeamSwitcher, isSuccessTeamSwitcher, setIsSuccessTeamSwitcher, leftPanel, platformName, productName, profileMenuItems = [], supportMenuItems = [], renderPrivacyRedirect = true, renderPrivacyStatement = true, rightPanel, handleShowTutorial, refetchUser, refetchNavigation, skipToContentProps, templateMeteringEvent, trackEvent, triggerEvent, tutorialScreenToShow, user, userTeams, userTeamsAssets, enableIcaMacs, }) {
21
+ function UIShell({ analyticsHelpers, baseEnvUrl, carbonTheme = "g10", config, createJoinTeamTrigger, enableTeamSwitcher = true, history, isLaunchpad = false, isLoadingTeamSwitcher, isSuccessTeamSwitcher, setIsSuccessTeamSwitcher, leftPanel, platformName, productName, profileMenuItems = [], supportMenuItems = [], renderPrivacyRedirect = true, renderPrivacyStatement = true, rightPanel, handleShowTutorial, refetchUser, refetchUserTeams, refetchNavigation, skipToContentProps, templateMeteringEvent, trackEvent, triggerEvent, tutorialScreenToShow, user, userTeams, userTeamsAssets, enableIcaMacs, }) {
22
22
  // Support base header .e.g for an error state
23
23
  if (!config) {
24
24
  return (React.createElement(QueryClientProvider, { client: queryClient },
25
- React.createElement(Header, { baseEnvUrl: baseEnvUrl ?? "", baseServicesUrl: "", carbonTheme: carbonTheme, enableAppSwitcher: false, enableNotifications: false, enableNotificationsCount: false, productName: productName || platformName || "", user: user })));
25
+ React.createElement(Header, { baseEnvUrl: baseEnvUrl ?? "", baseServicesUrl: "", carbonTheme: carbonTheme, enableAppSwitcher: false, enableNotifications: false, enableNotificationsCount: false, enableTeamSwitcher: enableTeamSwitcher, productName: productName || platformName || "", user: user })));
26
26
  }
27
27
  const { features, navigation, platform, platformMessage } = config;
28
28
  const names = getProductAndPlatformNames({ productName, platformName, platform });
@@ -63,8 +63,8 @@ function UIShell({ analyticsHelpers, baseEnvUrl, carbonTheme = "g10", config, cr
63
63
  */
64
64
  const isPrivacyStatementDisabled = renderPrivacyStatement === false || features?.["consent.enabled"] === false;
65
65
  return (React.createElement(QueryClientProvider, { client: queryClient },
66
- React.createElement(Header, { analyticsHelpers: analyticsHelpers, baseEnvUrl: platform.baseEnvUrl, baseServicesUrl: platform.baseServicesUrl, carbonTheme: carbonTheme, createJoinTeamTrigger: createJoinTeamTrigger, enableAppSwitcher: isAppSwitcherEnabled, instanceSwitcherEnabled: instanceSwitcherEnabled, enableNotifications: isNotificationsEnabled, enableNotificationsCount: isNotificationsCountEnabled, leftPanel: leftPanel, navLinks: navigation, platform: platform, platformMessage: platformMessage, prefixName: names.platformName, productName: names.productName, rightPanel: rightPanel, requestSummary: user?.requestSummary, skipToContentProps: skipToContentProps, templateMeteringEvent: templateMeteringEvent, triggerEvent: triggerEvent, profileMenuItems: [
67
- isUserEnabled && (React.createElement(ProfileSettingsMenuItem, { key: "profile-settings", baseServicesUrl: platform.baseServicesUrl, src: `${platform.baseServicesUrl}/users/image/${user?.email}`, userName: user?.displayName ?? user?.name })),
66
+ React.createElement(Header, { analyticsHelpers: analyticsHelpers, baseEnvUrl: platform.baseEnvUrl, baseServicesUrl: platform.baseServicesUrl, carbonTheme: carbonTheme, createJoinTeamTrigger: createJoinTeamTrigger, enableAppSwitcher: isAppSwitcherEnabled, instanceSwitcherEnabled: instanceSwitcherEnabled, enableNotifications: isNotificationsEnabled, enableNotificationsCount: isNotificationsCountEnabled, enableTeamSwitcher: enableTeamSwitcher, leftPanel: leftPanel, navLinks: navigation, platform: platform, platformMessage: platformMessage, prefixName: names.platformName, productName: names.productName, rightPanel: rightPanel, requestSummary: user?.requestSummary, skipToContentProps: skipToContentProps, templateMeteringEvent: templateMeteringEvent, triggerEvent: triggerEvent, profileMenuItems: [
67
+ isUserEnabled && (React.createElement(ProfileSettingsMenuItem, { key: "profile-settings", baseServicesUrl: platform.baseServicesUrl, src: `${platform.baseServicesUrl}/users/image/${user?.email}`, userName: user?.displayName ?? user?.name, refetchUser: refetchUser, refetchUserTeams: refetchUserTeams, refetchNavigation: refetchNavigation })),
68
68
  isSendMailEnabled && (React.createElement(HeaderMenuItem, { key: "email-preferences", href: `${platform.baseEnvUrl}/launchpad/email-preferences`, icon: React.createElement(Email, null), kind: "internal", text: "Email Preferences", type: "link" })),
69
69
  !isPrivacyStatementDisabled && (React.createElement(PrivacyStatementMenuItem, { key: "privacy-statement", baseServicesUrl: platform.baseServicesUrl, platformEmail: platform?.platformEmail })),
70
70
  ...profileMenuItems,
@@ -0,0 +1,13 @@
1
+ /*
2
+ IBM Confidential
3
+ 694970X, 69497O0
4
+ © Copyright IBM Corp. 2022, 2024
5
+ */
6
+ const TEAM_TYPES = {
7
+ ACCOUNT: "account",
8
+ PERSONAL: "personal",
9
+ PROJECT: "project",
10
+ STANDARD: "standard",
11
+ };
12
+
13
+ export { TEAM_TYPES };
@@ -366,6 +366,7 @@ type Props$G = {
366
366
  className?: string;
367
367
  createJoinTeamTrigger?: Function;
368
368
  enableAppSwitcher?: boolean;
369
+ enableTeamSwitcher?: boolean;
369
370
  instanceSwitcherEnabled?: boolean;
370
371
  enableNotifications?: boolean;
371
372
  enableNotificationsCount?: boolean;
@@ -1436,6 +1437,7 @@ type Props = {
1436
1437
  };
1437
1438
  platformMessage?: any;
1438
1439
  };
1440
+ enableTeamSwitcher?: boolean;
1439
1441
  history?: any;
1440
1442
  isLaunchpad?: boolean;
1441
1443
  isLoadingTeamSwitcher?: boolean;
@@ -1456,6 +1458,7 @@ type Props = {
1456
1458
  component: React.ReactNode;
1457
1459
  };
1458
1460
  refetchUser?: Function;
1461
+ refetchUserTeams?: Function;
1459
1462
  refetchNavigation?: Function;
1460
1463
  skipToContentProps?: {
1461
1464
  href?: string;
@@ -1481,6 +1484,6 @@ type Props = {
1481
1484
  handleShowTutorial?: Function;
1482
1485
  tutorialScreenToShow?: string;
1483
1486
  };
1484
- declare function UIShell({ analyticsHelpers, baseEnvUrl, carbonTheme, config, createJoinTeamTrigger, history, isLaunchpad, isLoadingTeamSwitcher, isSuccessTeamSwitcher, setIsSuccessTeamSwitcher, leftPanel, platformName, productName, profileMenuItems, supportMenuItems, renderPrivacyRedirect, renderPrivacyStatement, rightPanel, handleShowTutorial, refetchUser, refetchNavigation, skipToContentProps, templateMeteringEvent, trackEvent, triggerEvent, tutorialScreenToShow, user, userTeams, userTeamsAssets, enableIcaMacs, }: Props): React.JSX.Element;
1487
+ declare function UIShell({ analyticsHelpers, baseEnvUrl, carbonTheme, config, createJoinTeamTrigger, enableTeamSwitcher, history, isLaunchpad, isLoadingTeamSwitcher, isSuccessTeamSwitcher, setIsSuccessTeamSwitcher, leftPanel, platformName, productName, profileMenuItems, supportMenuItems, renderPrivacyRedirect, renderPrivacyStatement, rightPanel, handleShowTutorial, refetchUser, refetchUserTeams, refetchNavigation, skipToContentProps, templateMeteringEvent, trackEvent, triggerEvent, tutorialScreenToShow, user, userTeams, userTeamsAssets, enableIcaMacs, }: Props): React.JSX.Element;
1485
1488
 
1486
1489
  export { AdvantageSideNav, AutoSuggestBmrg as AutoSuggest, Avatar, CheckboxListComponent as CheckboxList, ComboBoxComponent as ComboBox, ComboBoxMultiSelect, ComposedModal, ConfirmModal, CreatableComponent as Creatable, DataDrivenInput, DateInputComponent as DateInput, DecisionButtons, DelayedRender, DynamicFormik, DynamicInput, Error, Error403, Error404, ErrorBoundary, ErrorDragon, ErrorFullPage, Error as ErrorMessage, ErrorPage, ErrorPageCore, FeatureHeader, FeatureHeaderSubtitle, FeatureHeaderTitle, FeatureNavTab, FeatureNavTabs, FeatureSideNav, FeatureSideNavFooter, FeatureSideNavHeader, FeatureSideNavLink, FeatureSideNavLinks, FlowModalContainer as FlowModal, FlowModalForm, FormInput, Header, _default as HeaderMenuItem, ImageModal, InputGovernor, Loading, MemberBar, Modal, ModalConfirmEdit, FlowModalContainer as ModalFlow, FlowModalForm as ModalFlowForm, ModalForm, ModalFunctionChildrenProps, ModalTrigger, NotificationsContainer, PlatformBanner, PlatformNotificationsContainer, Portal, PrivacyStatement, ProtectedRoute, RadioGroupComponent as RadioGroup, RichTextAreaComponent as RichTextArea, SimpleTeamService, Team, TextAreaComponent as TextArea, TextInputComponent as TextInput, ToastNotification, ToggleComponent as Toggle, TooltipHover, UIShell, User, UserTeams, notify };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@boomerang-io/carbon-addons-boomerang-react",
3
3
  "description": "Carbon Addons for Boomerang apps",
4
- "version": "4.6.14-beta.0",
4
+ "version": "4.6.14-beta.10",
5
5
  "author": {
6
6
  "name": "Tim Bula",
7
7
  "email": "timrbula@gmail.com"
@@ -39,13 +39,40 @@ IBM Confidential
39
39
  overflow: hidden;
40
40
  width: 100%;
41
41
 
42
- .#{$prefix}--header__menu-arrow {
42
+ .#{$prefix}--header-dropdown-menu-content {
43
+ align-items: center;
44
+ display: flex;
45
+ }
46
+
47
+ .#{$prefix}--header-dropdown-menu-content-text {
48
+ font-size: 0.875rem;
49
+ font-weight: 600;
50
+ line-height: 1.125rem;
51
+ letter-spacing: 0.01rem;
52
+ max-width: 14.5625rem;
53
+ overflow: hidden;
54
+ text-overflow: ellipsis;
55
+ white-space: nowrap;
56
+ }
57
+
58
+ .#{$prefix}--header-dropdown-menu-content-icon {
59
+ margin-left: 1rem;
43
60
  min-height: 1rem;
44
61
  min-width: 1rem;
62
+ transition: transform 150ms ease-in-out;
63
+ transform: rotate(0deg);
45
64
  }
46
65
 
47
66
  &[aria-expanded="true"] {
48
67
  background-color: var(--cds-layer-hover-01) !important;
68
+
69
+ .#{$prefix}--header-dropdown-menu-content-text {
70
+ width: 14.5625rem;
71
+ }
72
+
73
+ .#{$prefix}--header-dropdown-menu-content-icon {
74
+ transform: rotate(180deg);
75
+ }
49
76
  }
50
77
  }
51
78
 
@@ -4,7 +4,6 @@ IBM Confidential
4
4
  © Copyright IBM Corp. 2022, 2024
5
5
  */
6
6
 
7
-
8
7
  @use "../../global/config" as *;
9
8
  @use "../../global/utils";
10
9
  @use "../../global/themes/shell-tokens" as shell;
@@ -29,6 +28,7 @@ IBM Confidential
29
28
 
30
29
  .#{$prefix}--modal-content {
31
30
  color: shell.$bmrg-theme-primary;
31
+ mask-image: none !important;
32
32
  .#{$prefix}--bmrg-profile-settings__title {
33
33
  color: shell.$bmrg-theme-primary;
34
34
  font-size: utils.rem(14px);