@camunda/camunda-composite-components 0.11.0 → 0.12.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.
Files changed (20) hide show
  1. package/lib/esm/package.json +2 -2
  2. package/lib/esm/src/components/c3-navigation/c3-navigation-appbar/c3-navigation-appbar.js +117 -6
  3. package/lib/esm/src/components/c3-navigation/c3-navigation-sidebar/c3-navigation-sidebar-element.js +10 -5
  4. package/lib/esm/src/components/c3-navigation/c3-navigation-sidebar/c3-navigation-sidebar.types.d.ts +3 -0
  5. package/lib/esm/src/components/c3-navigation/c3-navigation-sidebar/c3-notification-sidebar.js +2 -2
  6. package/lib/esm/src/components/c3-navigation/c3-navigation.js +3 -9
  7. package/lib/esm/src/components/c3-navigation/c3-navigation.types.d.ts +1 -0
  8. package/lib/esm/src/components/c3-navigation/c3-notification-provider/c3-notification-provider.d.ts +1 -0
  9. package/lib/esm/src/components/c3-navigation/c3-notification-provider/c3-notification-provider.js +28 -24
  10. package/lib/esm/src/components/c3-navigation/c3-org-name.d.ts +6 -0
  11. package/lib/esm/src/components/c3-navigation/c3-org-name.js +37 -0
  12. package/lib/esm/src/components/c3-navigation/c3-org-sidebar/c3-org-sidebar.js +102 -32
  13. package/lib/esm/src/components/c3-navigation/c3-org-sidebar/components.d.ts +10 -0
  14. package/lib/esm/src/components/c3-navigation/c3-org-sidebar/components.js +32 -6
  15. package/lib/esm/src/components/c3-user-configuration/c3-profile-provider/c3-profile-provider.d.ts +2 -0
  16. package/lib/esm/src/components/c3-user-configuration/c3-profile-provider/c3-profile-provider.js +11 -7
  17. package/lib/esm/src/components/styles.d.ts +1 -0
  18. package/lib/esm/src/components/styles.js +6 -0
  19. package/lib/esm/src/utils/camunda.types.d.ts +3 -0
  20. package/package.json +2 -2
@@ -4,7 +4,7 @@
4
4
  "type": "git",
5
5
  "url": "git+https://github.com/camunda-cloud/camunda-composite-components.git"
6
6
  },
7
- "version": "0.10.1-rc.2",
7
+ "version": "0.11.1-rc.1",
8
8
  "scripts": {
9
9
  "clean": "rimraf lib/",
10
10
  "build": "yarn clean && tsc",
@@ -34,7 +34,7 @@
34
34
  "@babel/preset-env": "7.25.7",
35
35
  "@babel/preset-react": "7.25.7",
36
36
  "@babel/preset-typescript": "7.25.7",
37
- "@carbon/react": "1.55.0",
37
+ "@carbon/react": "1.66.0",
38
38
  "@mdx-js/react": "3.0.1",
39
39
  "@playwright/test": "1.45.2",
40
40
  "@semantic-release/changelog": "6.0.3",
@@ -1,20 +1,116 @@
1
- import React, { useEffect, useState } from "react";
1
+ import React, { useCallback, useEffect, useState } from "react";
2
2
  import { Close } from "@carbon/react/icons";
3
3
  import { useOnClickOutside } from "../helpers";
4
- import { HeaderGlobalAction, HeaderMenuItem, HeaderSideNavItems, SideNavItems, SideNavLink, SideNavMenu, SideNavMenuItem, } from "@carbon/react";
4
+ import { FormLabel, HeaderGlobalAction, HeaderMenuItem, HeaderSideNavItems, Modal, SideNavItems, SideNavLink, SideNavMenu, SideNavMenuItem, } from "@carbon/react";
5
5
  import { C3AppMenuIcon } from "../../../assets/c3-icons";
6
6
  import { useC3Profile } from "../../c3-user-configuration/c3-profile-provider/c3-profile-provider";
7
7
  import { useC3UserConfiguration } from "../../c3-user-configuration/c3-user-configuration-provider";
8
8
  import { APPS } from "../../../utils/camunda";
9
9
  import { NavWrapper, SideNav } from "./components";
10
+ const getOrgLink = (app, orgId, domain) => {
11
+ switch (app) {
12
+ case "console": {
13
+ return `https://console.${domain}/org/${orgId}`;
14
+ }
15
+ case "modeler": {
16
+ return `https://modeler.${domain}/login?returnUrl=/org/${orgId}`;
17
+ }
18
+ default: {
19
+ return "#";
20
+ }
21
+ }
22
+ };
23
+ const OrgPickerModal = ({ isOpen, onCancel, orgs, activeOrg, loadingStatus, appToNavigateTo, domain, }) => {
24
+ const hasNoTeams = Object.values(orgs ?? {})?.every(({ org }) => {
25
+ return !org?.name;
26
+ });
27
+ const getClustersToRender = (clusters) => {
28
+ const hasAppReadPermission = activeOrg?.permissions?.cluster?.[appToNavigateTo]?.read;
29
+ const clustersToRender = clusters?.filter(({ status, endpoints }) => status[appToNavigateTo] === "Healthy" &&
30
+ endpoints[appToNavigateTo] &&
31
+ hasAppReadPermission);
32
+ return clustersToRender;
33
+ };
34
+ const hasNoTeamsWithClusters = Object.values(orgs ?? {})?.every(({ clusters }) => {
35
+ const isConsoleOrModeler = [APPS[0], APPS[1]].includes(appToNavigateTo);
36
+ return !isConsoleOrModeler && getClustersToRender(clusters).length === 0;
37
+ });
38
+ return (React.createElement(Modal, { danger: true, open: isOpen, modalHeading: "Select a team", onRequestClose: onCancel, passiveModal: true, loadingStatus: loadingStatus, size: "sm" },
39
+ React.createElement("div", { style: { marginLeft: "-1rem" } },
40
+ React.createElement(FormLabel, { style: {
41
+ paddingTop: "15px",
42
+ paddingLeft: "1rem",
43
+ } }, hasNoTeams
44
+ ? "No teams found"
45
+ : hasNoTeamsWithClusters
46
+ ? "No teams with clusters found"
47
+ : "Teams"),
48
+ React.createElement("div", { style: {
49
+ marginTop: "-1rem",
50
+ } },
51
+ React.createElement(SideNavItems, null, Object.values(orgs ?? {})?.map(({ org, clusters }) => {
52
+ const isConsoleOrModeler = [APPS[0], APPS[1]].includes(appToNavigateTo);
53
+ const toOrg = getOrgLink(appToNavigateTo, org.uuid, domain ?? "");
54
+ if (isConsoleOrModeler) {
55
+ return (React.createElement(SideNavLink, { key: org?.uuid, href: toOrg }, org?.name));
56
+ }
57
+ const clustersToRender = getClustersToRender(clusters);
58
+ if (clustersToRender.length === 0) {
59
+ return null;
60
+ }
61
+ return (React.createElement(SideNavMenu, { key: org?.uuid, title: org?.name }, clustersToRender?.map((cluster) => {
62
+ return (React.createElement(SideNavMenuItem, { key: cluster.uuid, href: cluster.endpoints[appToNavigateTo] }, cluster.name));
63
+ })));
64
+ }))))));
65
+ };
10
66
  export const C3NavigationAppBar = ({ app: appProps, appBar, forwardRef, navbar, }) => {
11
67
  const { currentApp, domain, analyticsTrack, currentClusterUuid } = useC3UserConfiguration();
12
- const { clusters, activeOrg, isEnabled } = useC3Profile();
68
+ const { orgs, clusters, activeOrg, isEnabled, loadClustersById } = useC3Profile();
13
69
  const [appBarOpen, setAppBarOpen] = useState(appBar.isOpen || false);
14
70
  const { setPanelRef: panelRef, setIconRef: iconRef } = useOnClickOutside(() => setAppBarOpen(false));
15
71
  const [appElements, setAppElements] = useState([]);
72
+ const [loadingStatus, setLoadingStatus] = useState("inactive");
73
+ const [clustersByOrgId, setClustersByOrgId] = useState(null);
74
+ const [appToNavigateTo, setAppToNavigateTo] = useState(APPS[0]);
16
75
  if (!appBar.elements && !isEnabled)
17
76
  console.warn("No app elements and user config provided. Please provide at least one of them.");
77
+ const isMemberOfTeam = useCallback((orgUuid) => orgs?.some(({ uuid }) => uuid === orgUuid) || false, [orgs]);
78
+ const getClustersForSuperOrg = useCallback(async () => {
79
+ const updatedClusterByOrgId = {};
80
+ await Promise.all(activeOrg?.childOrganizations
81
+ ?.filter((team) => isMemberOfTeam(team.uuid))
82
+ .map((org) => loadClustersById(org.uuid)?.then(({ result }) => {
83
+ updatedClusterByOrgId[org.uuid] = {
84
+ org,
85
+ clusters: result ?? [],
86
+ };
87
+ })) ?? []);
88
+ setClustersByOrgId(updatedClusterByOrgId);
89
+ }, [activeOrg, isMemberOfTeam]);
90
+ const handleSuperOrg = useCallback(() => {
91
+ if (!activeOrg?.uuid) {
92
+ return;
93
+ }
94
+ setIsOrgPickerModalOpen(true);
95
+ if (clustersByOrgId) {
96
+ return;
97
+ }
98
+ setLoadingStatus("active");
99
+ getClustersForSuperOrg()
100
+ .catch((error) => console.error(error))
101
+ .finally(() => {
102
+ setLoadingStatus("finished");
103
+ });
104
+ }, [clustersByOrgId, activeOrg, getClustersForSuperOrg]);
105
+ useEffect(() => {
106
+ if (activeOrg?.isSuperOrg) {
107
+ getClustersForSuperOrg()
108
+ .catch((error) => console.error(error))
109
+ .finally(() => {
110
+ setLoadingStatus("finished");
111
+ });
112
+ }
113
+ }, [activeOrg, getClustersForSuperOrg]);
18
114
  useEffect(() => {
19
115
  if (appBar.elements)
20
116
  return;
@@ -76,12 +172,24 @@ export const C3NavigationAppBar = ({ app: appProps, appBar, forwardRef, navbar,
76
172
  }
77
173
  }
78
174
  }
79
- if (element.href || element.routeProps || element.subElements)
175
+ if (element.href || element.routeProps || element.subElements) {
176
+ if (activeOrg.isSuperOrg) {
177
+ element.href = "#";
178
+ element.routeProps = null;
179
+ element.onClick = () => {
180
+ setAppToNavigateTo(app);
181
+ handleSuperOrg();
182
+ // probs want to track?
183
+ // analyticsTrack?.(`${app}:open`, { currentApp: app })
184
+ };
185
+ }
80
186
  defaultElements.push(element);
187
+ }
81
188
  }
82
189
  setAppElements(defaultElements);
83
- }, [JSON.stringify(clusters), currentApp, domain]);
84
- const appBarElements = appBar.elements || (clusters ? appElements : null);
190
+ }, [clusters, currentApp, domain, handleSuperOrg, getClustersForSuperOrg]);
191
+ const appBarElements = appBar.elements || (clusters || clustersByOrgId ? appElements : null);
192
+ const [isOrgPickerModalOpen, setIsOrgPickerModalOpen] = useState(false);
85
193
  return (React.createElement(React.Fragment, null,
86
194
  React.createElement(HeaderGlobalAction
87
195
  // eslint-disable-next-line
@@ -95,6 +203,9 @@ export const C3NavigationAppBar = ({ app: appProps, appBar, forwardRef, navbar,
95
203
  /* eslint-disable-next-line @typescript-eslint/ban-ts-comment */
96
204
  /* @ts-ignore */
97
205
  leaveDelayMs: 100 }, appBarOpen ? React.createElement(Close, { size: 20 }) : React.createElement(C3AppMenuIcon, { size: 20 })),
206
+ React.createElement(OrgPickerModal, { activeOrg: activeOrg, appToNavigateTo: appToNavigateTo, isOpen: isOrgPickerModalOpen, orgs: clustersByOrgId, onCancel: () => {
207
+ setIsOrgPickerModalOpen(false);
208
+ }, loadingStatus: loadingStatus, domain: domain }),
98
209
  React.createElement(NavWrapper, null,
99
210
  React.createElement(SideNav, { ref: panelRef, "aria-label": appBar.ariaLabel || "Side Navigation", expanded: appBarOpen, isPersistent: false },
100
211
  React.createElement(SideNavItems, null,
@@ -1,4 +1,4 @@
1
- import { Button } from "@carbon/react";
1
+ import { Button, SideNavLink } from "@carbon/react";
2
2
  import React, { useEffect, useRef, useState } from "react";
3
3
  import { SwitcherDivider } from "./components";
4
4
  import styled from "styled-components";
@@ -7,6 +7,10 @@ const Row = styled.div `
7
7
  justify-content: start;
8
8
  align-items: center;
9
9
 
10
+ li {
11
+ list-style-type: none;
12
+ }
13
+
10
14
  .cds--switcher__item:nth-child(1) {
11
15
  margin-block-start: 0;
12
16
  }
@@ -22,7 +26,8 @@ const Row = styled.div `
22
26
  const C3NavigationSidebarElement = (props) => {
23
27
  const sideBarElementRef = useRef(null);
24
28
  const [isOverflown, setIsOverflown] = useState(false);
25
- const { overflowMenu } = props.element;
29
+ const { overflowMenu, isActive, isNavLink } = props.element;
30
+ const Element = isNavLink ? SideNavLink : Button;
26
31
  const handleSetIsOverflown = () => {
27
32
  const element = sideBarElementRef.current;
28
33
  setIsOverflown(element ? element.offsetWidth < element.scrollWidth : false);
@@ -35,7 +40,7 @@ const C3NavigationSidebarElement = (props) => {
35
40
  return (React.createElement(React.Fragment, null,
36
41
  props.element.preceedingDivider && React.createElement(SwitcherDivider, null),
37
42
  React.createElement(Row, null,
38
- React.createElement(Button, { style: {
43
+ React.createElement(Element, { style: {
39
44
  width: overflowMenu
40
45
  ? `calc(14rem - ${props.scrollBarWidth}px)`
41
46
  : `calc(16rem - ${props.scrollBarWidth}px)`,
@@ -43,14 +48,14 @@ const C3NavigationSidebarElement = (props) => {
43
48
  (!("elements" in props.sideBar) || !props.sideBar.elements)
44
49
  ? { marginTop: "1.5rem" }
45
50
  : {}),
46
- }, size: "sm", kind: props.element.kind ?? "ghost", className: "cds--switcher__item", onClick: () => {
51
+ }, size: "sm", kind: props.element.kind ?? "ghost", className: `cds--switcher__item ${isActive ? "cds--side-nav__item--active" : ""}`, onClick: () => {
47
52
  if (props.element.onClick) {
48
53
  props.element.onClick();
49
54
  }
50
55
  if (props.sideBar.closeOnClick !== false) {
51
56
  props.setSideBarOpen(false);
52
57
  }
53
- }, tabIndex: props.itemTabIndex, renderIcon: props.element.renderIcon },
58
+ }, tabIndex: props.itemTabIndex, renderIcon: props.element.renderIcon, isActive: isNavLink ? isActive : undefined },
54
59
  React.createElement("span", { ref: sideBarElementRef, title: isOverflown ? props.element.label : "", style: {
55
60
  overflow: "hidden",
56
61
  textOverflow: "ellipsis",
@@ -18,6 +18,7 @@ export type CamundaOrg = {
18
18
  label: string;
19
19
  onClick: () => void;
20
20
  };
21
+ teamsLabel?: string;
21
22
  };
22
23
  export type C3NavigationOrgSideBarProps = C3NavigationSideBarBaseProps & {
23
24
  type: "org";
@@ -26,6 +27,8 @@ export type C3NavigationOrgSideBarProps = C3NavigationSideBarBaseProps & {
26
27
  };
27
28
  switchToOrg?: (orgId: string) => void;
28
29
  manageOrg?: (orgId: string) => void;
30
+ manageSuperorg?: (orgId: string) => void;
31
+ manageTeam?: (orgId: string, teamId: string) => void;
29
32
  };
30
33
  export type C3NavigationInfoSideBarProps = C3NavigationSideBarBaseProps & {
31
34
  type: "info";
@@ -43,7 +43,7 @@ const EmptyStateDescription = styled(NotificationDescription) `
43
43
  `;
44
44
  export const C3NotificationSidebar = ({ sideBar }) => {
45
45
  const { onLinkClick } = sideBar;
46
- const { notifications, markAsRead, dismiss, markAllAsRead, dismissAll, analytics, enabled, } = useContext(C3NotificationContext);
46
+ const { notifications, isFetching, markAsRead, dismiss, markAllAsRead, dismissAll, analytics, enabled, } = useContext(C3NotificationContext);
47
47
  const [unreadNotifications, setUnreadNotifications] = useState([]);
48
48
  const hasUnreadNotifications = notifications?.some(({ state }) => state === "new");
49
49
  const { isOpen } = useNotificationSidebarState();
@@ -86,7 +86,7 @@ export const C3NotificationSidebar = ({ sideBar }) => {
86
86
  ...sideBar,
87
87
  ariaLabel: sideBar.ariaLabel || "Notification Sidebar",
88
88
  callbacks: { beforeOpening, afterClosing },
89
- }, icon: hasUnreadNotifications ? (React.createElement(C3NotificationsUnreadIcon, { size: 20 })) : (React.createElement(NotificationIcon, { size: 20, "aria-label": "Notifications" })) },
89
+ }, icon: hasUnreadNotifications && !isFetching ? (React.createElement(C3NotificationsUnreadIcon, { size: 20 })) : (React.createElement(NotificationIcon, { size: 20, "aria-label": "Notifications" })) },
90
90
  React.createElement(PanelHeader, null,
91
91
  React.createElement(PanelTitle, null, "Notifications"),
92
92
  notifications.length > 0 && (
@@ -17,6 +17,7 @@ import { useC3HelpCenter } from "../c3-help-center/c3-help-center-provider";
17
17
  import { useC3Profile } from "../c3-user-configuration/c3-profile-provider/c3-profile-provider";
18
18
  import { HelpCenterHint } from "../c3-help-center/help-center-hint";
19
19
  import { useC3UserConfiguration } from "../c3-user-configuration/c3-user-configuration-provider";
20
+ import { OrgName } from "./c3-org-name";
20
21
  import { Time, Warning } from "@carbon/react/icons";
21
22
  /**
22
23
  * UI SHELL
@@ -172,7 +173,7 @@ export const C3Navigation = ({ app, appBar, forwardRef, navbar, orgSideBar, info
172
173
  marginTop: "0.75rem",
173
174
  } },
174
175
  React.createElement(Toggletip, null,
175
- React.createElement(ToggletipButton, { label: buttonLabel },
176
+ React.createElement(ToggletipButton, { as: "span", label: buttonLabel },
176
177
  React.createElement(Tag, { type: tag.color, renderIcon: tag.renderIcon, style: {
177
178
  margin: "0",
178
179
  cursor: "pointer",
@@ -192,14 +193,7 @@ export const C3Navigation = ({ app, appBar, forwardRef, navbar, orgSideBar, info
192
193
  }),
193
194
  (clusterUuid || currentClusterUuid) && (React.createElement(ClusterTagWrapper, null,
194
195
  React.createElement(C3ClusterTag, { clusterUuid: clusterUuid || currentClusterUuid || "", conditionalRendering: options?.conditionalTagRendering }))),
195
- orgName && (React.createElement("div", { className: "bodyText", style: {
196
- fontSize: "14px",
197
- lineHeight: "3rem",
198
- textOverflow: "ellipsis",
199
- whiteSpace: "nowrap",
200
- overflow: "hidden",
201
- maxWidth: "150px",
202
- } }, orgName))),
196
+ orgName && (React.createElement(OrgName, { orgName: orgName, isSuperOrg: activeOrg?.isSuperOrg, activeSuperOrg: activeOrg?.superOrganization?.name }))),
203
197
  actionButtons && React.createElement(C3ActionButtons, { elements: actionButtons }),
204
198
  notificationSideBar && (React.createElement(C3NotificationSidebar, { sideBar: {
205
199
  ...notificationSideBar,
@@ -26,6 +26,7 @@ export interface C3NavigationElementProps {
26
26
  subElements?: C3NavigationElementProps[];
27
27
  preceedingDivider?: boolean;
28
28
  overflowMenu?: React.ReactNode;
29
+ isNavLink?: boolean;
29
30
  }
30
31
  export interface C3NavigationNavBarProps {
31
32
  elements: Array<{
@@ -14,6 +14,7 @@ export type LinkProps = {
14
14
  };
15
15
  export type C3NotificationContextValue = {
16
16
  enabled: boolean;
17
+ isFetching: boolean;
17
18
  notifications: Notification[];
18
19
  markAsRead: (notification: Notification) => void;
19
20
  markAllAsRead: (notifications: Notification[]) => void;
@@ -1,8 +1,9 @@
1
- import React, { useContext, useEffect, useState, } from "react";
1
+ import React, { useContext, useEffect, useRef, useState, } from "react";
2
2
  import { NotificationService, } from "../../../api/notifications";
3
3
  import { C3UserConfigurationContext } from "../../c3-user-configuration/c3-user-configuration-provider";
4
4
  export const C3NotificationContext = React.createContext({
5
5
  enabled: false,
6
+ isFetching: true,
6
7
  notifications: [],
7
8
  markAsRead: () => undefined,
8
9
  markAllAsRead: () => undefined,
@@ -12,44 +13,46 @@ export const C3NotificationContext = React.createContext({
12
13
  });
13
14
  const C3NotificationProvider = ({ children, }) => {
14
15
  const [notifications, setNotifications] = useState([]);
15
- const [isFetched, setFetched] = useState(false);
16
- const [activeOrganizationId, setActiveOrganizationId] = useState("");
17
- const [isEventStreamAvailable, setEventStreamAvailable] = useState(false);
16
+ const [isFetching, setIsFetching] = useState(true);
17
+ const isFetched = useRef(false);
18
+ const isEventStreamAvailable = useRef(false);
19
+ const activeOrganizationId = useRef("");
18
20
  const config = useContext(C3UserConfigurationContext);
19
21
  const enabled = !!config && !!config.activeOrganizationId && !!config.userToken;
20
22
  // if the organization changes, we need to reset the state
21
- if (enabled && config.activeOrganizationId !== activeOrganizationId) {
22
- setActiveOrganizationId(config.activeOrganizationId);
23
- setFetched(false);
24
- setNotifications([]);
23
+ if (enabled && config.activeOrganizationId !== activeOrganizationId.current) {
24
+ isFetched.current = false;
25
25
  }
26
- if (enabled && !isFetched && config.userToken) {
27
- NotificationService.getNotifications(config).then(({ result }) => {
28
- if (result)
29
- setNotifications(result);
30
- setFetched(true);
31
- });
32
- }
33
- if (enabled && isFetched && !isEventStreamAvailable) {
34
- setEventStreamAvailable(true);
26
+ if (enabled && isFetched.current && !isEventStreamAvailable.current) {
27
+ isEventStreamAvailable.current = true;
35
28
  NotificationService.notificationsStream(config, (notification) => {
36
- if (notification.orgId === activeOrganizationId) {
37
- setNotifications(NotificationService.updateNotifications(notifications, notification));
29
+ if (notification.orgId === config.activeOrganizationId) {
30
+ setNotifications((currentNotifications) => NotificationService.updateNotifications(currentNotifications, notification));
38
31
  }
39
32
  });
40
33
  }
41
34
  useEffect(() => {
42
- if (enabled && config.userToken) {
43
- NotificationService.getNotifications(config).then(({ result }) => {
35
+ const orgHasChanged = activeOrganizationId.current !== config.activeOrganizationId;
36
+ if (enabled && !isFetched.current && config.userToken && orgHasChanged) {
37
+ setIsFetching(true);
38
+ NotificationService.getNotifications(config)
39
+ .then(({ result }) => {
44
40
  if (result)
45
41
  setNotifications(result);
46
- setFetched(true);
42
+ isFetched.current = true;
43
+ activeOrganizationId.current = config.activeOrganizationId;
44
+ })
45
+ .catch(() => {
46
+ // ignore
47
+ })
48
+ .finally(() => {
49
+ setIsFetching(false);
47
50
  });
48
51
  }
49
- }, [config?.userToken]);
52
+ }, [config?.userToken, enabled, isFetched, config.activeOrganizationId]);
50
53
  const changeState = (newState, { uuid, state }) => {
51
54
  if (enabled && state !== newState) {
52
- setNotifications(NotificationService.updateNotificationState(notifications, uuid, newState));
55
+ setNotifications((currentNotifications) => NotificationService.updateNotificationState(currentNotifications, uuid, newState));
53
56
  NotificationService.changeState(config, uuid, newState);
54
57
  }
55
58
  };
@@ -90,6 +93,7 @@ const C3NotificationProvider = ({ children, }) => {
90
93
  dismiss,
91
94
  dismissAll,
92
95
  analytics,
96
+ isFetching,
93
97
  } }, children));
94
98
  };
95
99
  export function withNotifications(Component) {
@@ -0,0 +1,6 @@
1
+ import { FC } from "react";
2
+ export declare const OrgName: FC<{
3
+ orgName: string;
4
+ isSuperOrg?: boolean;
5
+ activeSuperOrg?: string;
6
+ }>;
@@ -0,0 +1,37 @@
1
+ import React from "react";
2
+ import styled from "styled-components";
3
+ import { body01, label01 } from "../styles";
4
+ const OrgNameWrapper = styled.div `
5
+ display: flex;
6
+ padding-right: var(--12-px-075-rem-spacing-04, 12px);
7
+ align-items: center;
8
+ gap: var(--16-px-1-rem-spacing-05, 16px);
9
+ align-self: stretch;
10
+ `;
11
+ const SuperOrgWrapper = styled.div `
12
+ display: flex;
13
+ flex-direction: column;
14
+ justify-content: center;
15
+ align-items: flex-start;
16
+ gap: var(--0-px-0-rem-spacing-00, 0px);
17
+ `;
18
+ const SuperOrgName = styled.div `
19
+ color: var(--cds-text-secondary, #c6c6c6);
20
+ ${label01}
21
+ `;
22
+ const TeamName = styled.div `
23
+ color: var(--cds-text-primary, #f4f4f4);
24
+ text-align: right;
25
+ ${body01}
26
+ `;
27
+ const SingleOrgName = styled.div `
28
+ font-size: 14px;
29
+ line-height: 3rem;
30
+ text-overflow: ellipsis;
31
+ white-space: nowrap;
32
+ overflow: hidden;
33
+ max-width: 150px;
34
+ `;
35
+ export const OrgName = ({ orgName, isSuperOrg, activeSuperOrg }) => (React.createElement(OrgNameWrapper, null, activeSuperOrg && !isSuperOrg ? (React.createElement(SuperOrgWrapper, { title: orgName },
36
+ React.createElement(SuperOrgName, null, activeSuperOrg),
37
+ React.createElement(TeamName, null, orgName))) : (React.createElement(SingleOrgName, { className: "bodyText", title: orgName }, orgName))));
@@ -1,50 +1,85 @@
1
1
  import React, { useState } from "react";
2
- import { Button, FormLabel } from "@carbon/react";
2
+ import { Button, FormLabel, TreeNode, TreeView, } from "@carbon/react";
3
3
  import { Enterprise } from "@carbon/react/icons";
4
4
  import C3NavigationSideBar from "../c3-navigation-sidebar/c3-navigation-sidebar";
5
5
  import { SwitcherDivider } from "../c3-navigation-sidebar/components";
6
6
  import { useOrgSidebarState } from "../c3-navigation-sidebar/c3-sidebar-state-provider";
7
7
  import { useC3Profile } from "../../c3-user-configuration/c3-profile-provider/c3-profile-provider";
8
8
  import { useC3UserConfiguration } from "../../c3-user-configuration/c3-user-configuration-provider";
9
- import { ActiveOrgName, ActiveOrgNameWrapper, ActiveOrgWrapper, ActiveOrgWrapperCustom, ConfirmLeaveModal, ManageOrgOverflowMenu, } from "./components";
9
+ import { ActiveOrgName, ActiveOrgNameWrapper, ActiveOrgWrapper, ActiveOrgWrapperCustom, ConfirmLeaveModal, ManageOrgOverflowMenu, OrgListWrapper, } from "./components";
10
10
  import { leaveOrganization } from "../../../api/organizations";
11
+ function renderTree({ nodes, expanded, withIcons = false }) {
12
+ if (!nodes) {
13
+ return;
14
+ }
15
+ return nodes.map(({ children, renderIcon, isExpanded, isDisabled, ...nodeProps }) => (React.createElement(TreeNode, { key: nodeProps.id, renderIcon: withIcons ? renderIcon : null, isExpanded: expanded ?? isExpanded, ...(isDisabled && {
16
+ style: { cursor: "not-allowed" },
17
+ "aria-disabled": "true",
18
+ }), ...nodeProps }, renderTree({ nodes: children, expanded, withIcons }))));
19
+ }
11
20
  const C3OrgSidebar = ({ sideBar }) => {
12
- const { customElements, switchToOrg, manageOrg, elements, ...sideBarProps } = sideBar;
21
+ const { customElements, switchToOrg, manageOrg, manageSuperorg, manageTeam, ...sideBarProps } = sideBar;
13
22
  const { isOpen, setIsOpen, scrollBarWidth } = useOrgSidebarState();
14
23
  const { userToken, decodedAudience, domain, analyticsTrack, setActiveOrgId } = useC3UserConfiguration();
15
24
  const { activeOrg, orgs, removeOrg } = useC3Profile();
25
+ const superOrgs = orgs?.filter((org) => org.isSuperOrg) || [];
26
+ const hasSuperOrgs = superOrgs?.length;
27
+ const isSuperOrgAdmin = activeOrg?.isSuperOrg
28
+ ? activeOrg?.permissions?.org?.settings?.read
29
+ : false;
30
+ const teams = activeOrg?.childOrganizations?.filter(({ uuid }) => activeOrg?.isSuperOrg &&
31
+ orgs?.some((org) => org.uuid === uuid) &&
32
+ activeOrg?.uuid !== uuid);
16
33
  const isCustomized = Boolean(customElements?.activeOrganization);
17
34
  const [isConfirmLeaveModalOpen, setIsConfirmLeaveModalOpen] = useState(false);
18
35
  const [orgToLeave, setOrgToLeave] = useState(null);
19
36
  const [loadingStatus, setLoadingStatus] = useState("inactive");
20
37
  const isLastOrg = orgs?.length === 1;
21
- const canUserLeaveOrg = (orgPermissions) => (!orgPermissions.org?.users?.owner?.update &&
38
+ const isMemberOfTeam = (orgUuid) => orgs?.some(({ uuid }) => uuid === orgUuid) || false;
39
+ const canUserLeaveOrg = (org) => (((isSuperOrgAdmin && isMemberOfTeam(org.uuid)) || !isSuperOrgAdmin) &&
40
+ !org.permissions?.org?.users?.owner?.update &&
22
41
  orgs?.length &&
23
42
  orgs.length > 1) ||
24
43
  false;
25
- const canUserManageOrg = (orgPermissions) => orgPermissions.org?.settings?.read || false;
44
+ const canUserManageOrg = (org) => (isSuperOrgAdmin && !org.permissions) ||
45
+ org.permissions?.org?.settings?.read ||
46
+ false;
26
47
  const onManageCustomOrg = () => {
27
48
  if (sideBar.closeOnClick !== false)
28
49
  setIsOpen(false);
29
50
  };
30
- const onManageOrg = (orgId) => {
51
+ const canSwitchToOrg = (orgId) => orgs?.some((org) => org.uuid === orgId);
52
+ const onManageOrg = ({ uuid, isSuperOrg }) => {
31
53
  setIsOpen(false);
32
54
  analyticsTrack?.("navBar:orgSettings:click", { orgId: activeOrg?.uuid });
33
- if (manageOrg) {
34
- manageOrg(orgId);
55
+ const isTeam = teams?.some((team) => team.uuid === uuid);
56
+ if (isSuperOrg && manageSuperorg) {
57
+ manageSuperorg(uuid);
58
+ }
59
+ else if (isSuperOrgAdmin && isTeam && manageTeam && activeOrg) {
60
+ manageTeam(activeOrg?.uuid, uuid);
61
+ }
62
+ else if (manageOrg) {
63
+ manageOrg(uuid);
35
64
  }
36
65
  else {
37
- window.location.href = `https://console.${domain}/org/${orgId}/management`;
66
+ window.location.href =
67
+ isSuperOrgAdmin &&
68
+ !isSuperOrg &&
69
+ teams?.some((team) => team.uuid === uuid)
70
+ ? `https://console.${domain}/org/${activeOrg?.uuid}/team/${uuid}`
71
+ : `https://console.${domain}/org/${uuid}/${isSuperOrg ? "team" : "management"}`;
38
72
  }
39
73
  };
40
74
  const activeOrganization = customElements?.activeOrganization || {
41
- activeLabel: "Active organization",
75
+ activeLabel: hasSuperOrgs ? "Organization" : "Active organization",
42
76
  orgName: activeOrg?.name || "",
43
77
  action: {
44
78
  onClick: onManageCustomOrg,
45
79
  label: "Manage",
46
80
  },
47
- otherLabel: "Other organizations",
81
+ otherLabel: "",
82
+ teamsLabel: "Teams",
48
83
  };
49
84
  const switchOrg = (orgId, track) => {
50
85
  setActiveOrgId(orgId);
@@ -53,17 +88,6 @@ const C3OrgSidebar = ({ sideBar }) => {
53
88
  switchToOrg?.(orgId);
54
89
  setIsOpen(false);
55
90
  };
56
- const orgElements = orgs
57
- ?.filter(({ uuid }) => uuid !== activeOrg?.uuid)
58
- .map((org) => ({
59
- key: org.uuid,
60
- label: org.name,
61
- onClick: () => switchOrg(org.uuid, true),
62
- overflowMenu: (React.createElement(ManageOrgOverflowMenu, { canManage: canUserManageOrg(org.permissions), canLeave: canUserLeaveOrg(org.permissions), isLastOrg: isLastOrg, orgName: org.name, onManage: () => onManageOrg(org.uuid), onRequestToLeave: () => {
63
- setOrgToLeave(org);
64
- setIsConfirmLeaveModalOpen(true);
65
- } })),
66
- }));
67
91
  const confirmLeaveOrg = async () => {
68
92
  if (orgToLeave && decodedAudience && userToken) {
69
93
  setLoadingStatus("active");
@@ -85,9 +109,27 @@ const C3OrgSidebar = ({ sideBar }) => {
85
109
  }
86
110
  };
87
111
  const itemTabIndex = isOpen ? undefined : -1;
112
+ const groupedBySuperOrg = orgs?.reduce((acc, curr) => {
113
+ const superOrgUuid = curr?.superOrganization?.uuid;
114
+ if (!superOrgUuid) {
115
+ acc[curr.uuid] = acc[curr.uuid] ?? {
116
+ ...curr,
117
+ childOrganizations: {},
118
+ };
119
+ return acc;
120
+ }
121
+ acc[superOrgUuid] = acc[superOrgUuid] ?? {
122
+ ...curr?.superOrganization,
123
+ childOrganizations: {},
124
+ };
125
+ acc[superOrgUuid].childOrganizations[curr.uuid] = {
126
+ ...curr,
127
+ childOrganizations: {},
128
+ };
129
+ return acc;
130
+ }, {}) ?? {};
88
131
  return (React.createElement(C3NavigationSideBar, { sideBar: {
89
132
  ...sideBarProps,
90
- elements: elements || orgElements,
91
133
  ariaLabel: sideBarProps.ariaLabel || "Organization Sidebars",
92
134
  }, icon: React.createElement(Enterprise, { size: 20 }) }, (customElements?.activeOrganization || activeOrg) && (React.createElement(React.Fragment, null,
93
135
  isCustomized ? (React.createElement(ActiveOrgWrapperCustom, null,
@@ -105,7 +147,7 @@ const C3OrgSidebar = ({ sideBar }) => {
105
147
  React.createElement(FormLabel, null, activeOrganization.activeLabel),
106
148
  React.createElement(ActiveOrgNameWrapper, null,
107
149
  React.createElement(ActiveOrgName, { className: "textPrimary", title: activeOrganization.orgName }, activeOrganization.orgName),
108
- activeOrg?.uuid && domain && (React.createElement(ManageOrgOverflowMenu, { canManage: canUserManageOrg(activeOrg?.permissions), canLeave: canUserLeaveOrg(activeOrg?.permissions), orgName: activeOrg?.name || "", isLastOrg: isLastOrg, onManage: () => onManageOrg(activeOrg?.uuid), onRequestToLeave: () => {
150
+ activeOrg?.uuid && domain && (React.createElement(ManageOrgOverflowMenu, { canManage: canUserManageOrg(activeOrg), canLeave: canUserLeaveOrg(activeOrg), isLastOrg: isLastOrg, isOrgMember: isMemberOfTeam(activeOrg.uuid), orgName: activeOrg.name, onManage: () => onManageOrg(activeOrg), onRequestToLeave: () => {
109
151
  setOrgToLeave(activeOrg);
110
152
  setIsConfirmLeaveModalOpen(true);
111
153
  } }))),
@@ -113,13 +155,41 @@ const C3OrgSidebar = ({ sideBar }) => {
113
155
  setIsConfirmLeaveModalOpen(false);
114
156
  setOrgToLeave(null);
115
157
  }, loadingStatus: loadingStatus }))),
116
- ((sideBar.elements && sideBar.elements.length > 0) ||
117
- (orgElements && orgElements.length > 0)) && (React.createElement(React.Fragment, null,
118
- React.createElement(SwitcherDivider, null),
119
- React.createElement(FormLabel, { style: {
120
- paddingTop: "15px",
121
- paddingLeft: "1rem",
122
- paddingBottom: ".25rem",
123
- } }, activeOrganization.otherLabel)))))));
158
+ React.createElement(SwitcherDivider, null),
159
+ React.createElement(OrgListWrapper, null,
160
+ React.createElement(TreeView, { label: "All organizations", ...(activeOrg?.uuid ? { selected: [activeOrg?.uuid] } : {}) }, renderTree({
161
+ nodes: Object.values(groupedBySuperOrg)?.map((element) => {
162
+ const userTeams = Object.values(element?.childOrganizations)?.filter((child) => isMemberOfTeam(child.uuid));
163
+ const defaultIsExpanded = (activeOrg?.uuid === element.uuid ||
164
+ !isMemberOfTeam(element.uuid) ||
165
+ userTeams?.some((team) => activeOrg?.uuid === team.uuid)) ??
166
+ false;
167
+ return {
168
+ children: userTeams?.length > 0
169
+ ? userTeams.map((team) => {
170
+ return {
171
+ id: team.uuid,
172
+ label: team.name,
173
+ isExpanded: false,
174
+ value: team.uuid,
175
+ renderIcon: null,
176
+ onSelect: canSwitchToOrg(team.uuid)
177
+ ? () => switchOrg(team.uuid, true)
178
+ : undefined,
179
+ };
180
+ })
181
+ : null,
182
+ id: element.uuid,
183
+ label: element.name,
184
+ value: element.uuid,
185
+ renderIcon: null,
186
+ isExpanded: defaultIsExpanded,
187
+ isDisabled: !isMemberOfTeam(element.uuid),
188
+ onSelect: canSwitchToOrg(element.uuid)
189
+ ? () => switchOrg(element.uuid, true)
190
+ : undefined,
191
+ };
192
+ }),
193
+ })))))));
124
194
  };
125
195
  export default C3OrgSidebar;
@@ -1,9 +1,14 @@
1
1
  import React, { FC } from "react";
2
2
  import { ModalProps } from "@carbon/react/es/components/Modal/Modal";
3
+ import { DropdownProps } from "@carbon/react/lib/components/Dropdown/Dropdown";
4
+ import { Organization } from "../../../utils/camunda.types";
3
5
  export declare const ActiveOrgWrapperCustom: import("styled-components").IStyledComponent<"web", import("styled-components/dist/types").FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>>;
4
6
  export declare const ActiveOrgWrapper: import("styled-components").IStyledComponent<"web", import("styled-components/dist/types").Substitute<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {
5
7
  $scrollBarWidth: number;
6
8
  }>>;
9
+ export declare const ActiveSuperorgWrapper: import("styled-components").IStyledComponent<"web", import("styled-components/dist/types").Substitute<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {
10
+ $scrollBarWidth: number;
11
+ }>>;
7
12
  export declare const ActiveOrgNameWrapper: import("styled-components").IStyledComponent<"web", import("styled-components/dist/types").FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>>;
8
13
  export declare const ActiveOrgName: import("styled-components").IStyledComponent<"web", import("styled-components/dist/types").Substitute<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {
9
14
  $isCustomized?: boolean | undefined;
@@ -19,7 +24,12 @@ export declare const ManageOrgOverflowMenu: FC<{
19
24
  canManage: boolean;
20
25
  canLeave: boolean;
21
26
  isLastOrg?: boolean;
27
+ isOrgMember: boolean;
22
28
  orgName: string;
23
29
  onManage: () => void;
24
30
  onRequestToLeave: () => void;
25
31
  }>;
32
+ export declare const StyledDropdown: FC<DropdownProps<Organization> & {
33
+ $scrollBarWidth: number;
34
+ }>;
35
+ export declare const OrgListWrapper: import("styled-components").IStyledComponent<"web", import("styled-components/dist/types").FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>>;
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- import { Modal, OverflowMenu, OverflowMenuItem, Popover, PopoverContent, } from "@carbon/react";
2
+ import { Dropdown, Modal, OverflowMenu, OverflowMenuItem, Popover, PopoverContent, } from "@carbon/react";
3
3
  import styled from "styled-components";
4
4
  export const ActiveOrgWrapperCustom = styled.div `
5
5
  padding: 1.5rem 1rem 15px;
@@ -11,6 +11,16 @@ export const ActiveOrgWrapper = styled.div `
11
11
  padding: 15px 0 0.5rem 1rem;
12
12
  width: ${({ $scrollBarWidth }) => `calc(16rem - ${$scrollBarWidth}px)`};
13
13
  `;
14
+ export const ActiveSuperorgWrapper = styled.div `
15
+ padding: 24px 0 0.5rem 0;
16
+ width: ${({ $scrollBarWidth }) => `calc(16rem - ${$scrollBarWidth}px)`};
17
+ display: flex;
18
+ flex-direction: column;
19
+
20
+ label {
21
+ padding-left: 1rem;
22
+ }
23
+ `;
14
24
  export const ActiveOrgNameWrapper = styled.div `
15
25
  display: flex;
16
26
  align-items: center;
@@ -47,18 +57,34 @@ const StyledOverflowMenu = styled(OverflowMenu) `
47
57
  width: 165px;
48
58
  }
49
59
  `;
50
- export const ManageOrgOverflowMenu = ({ canManage, canLeave, isLastOrg, onManage, onRequestToLeave, orgName, }) => {
60
+ export const ManageOrgOverflowMenu = ({ canManage, canLeave, isLastOrg, isOrgMember, onManage, onRequestToLeave, orgName, }) => {
51
61
  const [isPopoverShown, setIsPopoverShown] = React.useState(false);
52
62
  const leaveMenuItem = (React.createElement(OverflowMenuItem, { itemText: "Leave organization", disabled: !canLeave, onClick: onRequestToLeave, onMouseOver: () => setIsPopoverShown(true), onMouseLeave: () => setIsPopoverShown(false), "aria-label": `Leave organization - ${orgName}` }));
53
- const popoverLabel = isLastOrg
54
- ? "You need to be a member of at least one organization. Join a different organization first if you wish to leave."
55
- : "Owners cannot leave an organization directly. Assign another user as an owner if you wish to leave.";
63
+ const popoverLabel = !isOrgMember
64
+ ? "You are not a member of this team. You can only leave teams you are a member of."
65
+ : isLastOrg
66
+ ? "You need to be a member of at least one organization. Join a different organization first if you wish to leave."
67
+ : "Owners cannot leave an organization directly. Assign another user as an owner if you wish to leave.";
56
68
  return (React.createElement(StyledOverflowMenu, { size: "sm", flipped: true, "aria-label": "Organization options menu",
57
69
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
58
- // @ts-expect-error
59
70
  align: "top-right", "data-floating-menu-container": "cds--header-panel" },
60
71
  canManage && (React.createElement(OverflowMenuItem, { itemText: "Manage organization", onClick: onManage, "aria-label": `Manage organization - ${orgName}` })),
61
72
  canLeave ? (leaveMenuItem) : (React.createElement(PopoverWrapper, { open: isPopoverShown, label: popoverLabel, align: "bottom-right" },
62
73
  leaveMenuItem,
63
74
  React.createElement(PopoverContent, null, popoverLabel)))));
64
75
  };
76
+ export const StyledDropdown = styled(Dropdown) `
77
+ grid-gap: 0;
78
+
79
+ div {
80
+ max-width: calc(173px - ${({ $scrollBarWidth }) => $scrollBarWidth || 0}px);
81
+ }
82
+
83
+ .cds--list-box__menu {
84
+ max-inline-size: none;
85
+ min-inline-size: unset;
86
+ }
87
+ `;
88
+ export const OrgListWrapper = styled.div `
89
+ padding: 1rem 1rem 15px;
90
+ `;
@@ -1,6 +1,7 @@
1
1
  import React, { FC, PropsWithChildren } from "react";
2
2
  import { ResolvedTheme } from "./carbon-theme-provider";
3
3
  import { Cluster, Organization } from "../../../utils/camunda.types";
4
+ import { RequestResponse } from "../../../api/api";
4
5
  export type Theme = "light" | "dark" | "system";
5
6
  export declare const defaultTheme: "light";
6
7
  export type C3ProfileContextValue = {
@@ -14,6 +15,7 @@ export type C3ProfileContextValue = {
14
15
  reloadClusters: () => void;
15
16
  resolvedTheme: ResolvedTheme;
16
17
  onThemeChange: (newTheme: Theme) => void;
18
+ loadClustersById: (orgId: string) => Promise<RequestResponse<Cluster[] | null>> | undefined;
17
19
  };
18
20
  export declare const C3ProfileContext: React.Context<C3ProfileContextValue>;
19
21
  export declare const C3ProfileProvider: FC<PropsWithChildren>;
@@ -14,6 +14,7 @@ export const C3ProfileContext = createContext({
14
14
  reloadClusters: () => undefined,
15
15
  resolvedTheme: defaultTheme,
16
16
  onThemeChange: () => undefined,
17
+ loadClustersById: () => undefined,
17
18
  });
18
19
  export const C3ProfileProvider = ({ children }) => {
19
20
  const { decodedToken, decodedAudience, analyticsTrack, ...config } = useContext(C3UserConfigurationContext);
@@ -26,10 +27,15 @@ export const C3ProfileProvider = ({ children }) => {
26
27
  const isConfigValid = !!(config.userToken &&
27
28
  config.activeOrganizationId &&
28
29
  decodedAudience);
30
+ const loadClustersById = (orgId) => {
31
+ if (!isConfigValid)
32
+ return;
33
+ return getClusters(decodedAudience, config.userToken, orgId);
34
+ };
29
35
  const loadClusters = () => {
30
36
  if (!isConfigValid)
31
37
  return;
32
- getClusters(decodedAudience, config.userToken, config.activeOrganizationId).then(({ result }) => {
38
+ loadClustersById(config.activeOrganizationId)?.then(({ result }) => {
33
39
  if (result)
34
40
  setClusters(result);
35
41
  });
@@ -39,7 +45,8 @@ export const C3ProfileProvider = ({ children }) => {
39
45
  return;
40
46
  getOrgs(decodedAudience, config.userToken).then(({ result: res }) => {
41
47
  setOrgs(res?.sort(({ name: a }, { name: b }) => a.localeCompare(b)) || null);
42
- setActiveOrg(res?.find((org) => org.uuid === config.activeOrganizationId) || null);
48
+ const newActiveOrg = res?.find((org) => org.uuid === config.activeOrganizationId) || null;
49
+ setActiveOrg(newActiveOrg);
43
50
  });
44
51
  };
45
52
  const removeOrg = (orgId) => {
@@ -58,11 +65,7 @@ export const C3ProfileProvider = ({ children }) => {
58
65
  }
59
66
  }
60
67
  loadClusters();
61
- }, [
62
- config?.activeOrganizationId,
63
- JSON.stringify(decodedToken),
64
- decodedAudience,
65
- ]);
68
+ }, [config?.activeOrganizationId, decodedToken, decodedAudience]);
66
69
  useEffect(() => {
67
70
  const updateSystemTheme = ({ matches }) => {
68
71
  if (themeRef.current === "system")
@@ -108,6 +111,7 @@ export const C3ProfileProvider = ({ children }) => {
108
111
  reloadClusters: loadClusters,
109
112
  removeOrg,
110
113
  onThemeChange,
114
+ loadClustersById,
111
115
  } }, content));
112
116
  };
113
117
  export const useC3Profile = () => useContext(C3ProfileContext);
@@ -9,5 +9,6 @@ export declare const body02: import("styled-components").RuleSet<object>;
9
9
  export declare const Body02: import("styled-components").IStyledComponent<"web", import("styled-components/dist/types").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>, never>>;
10
10
  export declare const body01: import("styled-components").RuleSet<object>;
11
11
  export declare const Body01: import("styled-components").IStyledComponent<"web", import("styled-components/dist/types").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>, never>>;
12
+ export declare const label01: import("styled-components").RuleSet<object>;
12
13
  export declare const fontMapping: import("styled-components").RuleSet<object>;
13
14
  export declare const DefaultStyleWrapper: import("styled-components").IStyledComponent<"web", import("styled-components/dist/types").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>>;
@@ -53,6 +53,12 @@ export const body01 = css `
53
53
  export const Body01 = styled.p `
54
54
  ${body01}
55
55
  `;
56
+ export const label01 = css `
57
+ font-size: var(--cds-label-01-font-size);
58
+ font-weight: var(--cds-label-01-font-weight);
59
+ letter-spacing: var(--cds-label-01-letter-spacing);
60
+ line-height: var(--cds-label-01-line-height);
61
+ `;
56
62
  export const fontMapping = css `
57
63
  h1 {
58
64
  ${heading04}
@@ -32,6 +32,9 @@ export type Organization = {
32
32
  salesPlan: string;
33
33
  trialStateExpired: boolean;
34
34
  };
35
+ isSuperOrg?: boolean;
36
+ childOrganizations?: Organization[];
37
+ superOrganization?: Organization;
35
38
  };
36
39
  export type Cluster = {
37
40
  uuid: string;
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "type": "git",
5
5
  "url": "git+https://github.com/camunda-cloud/camunda-composite-components.git"
6
6
  },
7
- "version": "0.11.0",
7
+ "version": "0.12.0",
8
8
  "scripts": {
9
9
  "clean": "rimraf lib/",
10
10
  "build": "yarn clean && tsc",
@@ -34,7 +34,7 @@
34
34
  "@babel/preset-env": "7.25.7",
35
35
  "@babel/preset-react": "7.25.7",
36
36
  "@babel/preset-typescript": "7.25.7",
37
- "@carbon/react": "1.55.0",
37
+ "@carbon/react": "1.66.0",
38
38
  "@mdx-js/react": "3.0.1",
39
39
  "@playwright/test": "1.45.2",
40
40
  "@semantic-release/changelog": "6.0.3",