@camunda/camunda-composite-components 0.6.4 → 0.7.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 (44) hide show
  1. package/lib/esm/package.json +17 -17
  2. package/lib/esm/src/api/api.d.ts +7 -1
  3. package/lib/esm/src/api/api.js +18 -14
  4. package/lib/esm/src/api/help-center.d.ts +7 -7
  5. package/lib/esm/src/api/notifications.d.ts +2 -1
  6. package/lib/esm/src/api/organizations.d.ts +7 -1
  7. package/lib/esm/src/api/organizations.js +5 -0
  8. package/lib/esm/src/api/profile.d.ts +3 -2
  9. package/lib/esm/src/components/c3-app-teaser/c3-app-teaser-page.js +3 -3
  10. package/lib/esm/src/components/c3-empty-state/c3-empty-state.js +1 -1
  11. package/lib/esm/src/components/c3-help-center/c3-help-center.js +1 -1
  12. package/lib/esm/src/components/c3-help-center/help-center.js +19 -12
  13. package/lib/esm/src/components/c3-help-center/styles.d.ts +0 -1
  14. package/lib/esm/src/components/c3-help-center/tabs/feedback.js +7 -9
  15. package/lib/esm/src/components/c3-navigation/c3-navigation-appbar/c3-navigation-appbar.js +8 -2
  16. package/lib/esm/src/components/c3-navigation/c3-navigation-sidebar/c3-navigation-sidebar-element.d.ts +1 -0
  17. package/lib/esm/src/components/c3-navigation/c3-navigation-sidebar/c3-navigation-sidebar-element.js +50 -22
  18. package/lib/esm/src/components/c3-navigation/c3-navigation-sidebar/c3-navigation-sidebar.js +37 -7
  19. package/lib/esm/src/components/c3-navigation/c3-navigation-sidebar/c3-navigation-sidebar.types.d.ts +1 -0
  20. package/lib/esm/src/components/c3-navigation/c3-navigation-sidebar/c3-notification-sidebar.js +2 -2
  21. package/lib/esm/src/components/c3-navigation/c3-navigation-sidebar/c3-sidebar-state-provider.d.ts +2 -0
  22. package/lib/esm/src/components/c3-navigation/c3-navigation-sidebar/c3-sidebar-state-provider.js +24 -3
  23. package/lib/esm/src/components/c3-navigation/c3-navigation-sidebar/components.d.ts +0 -1
  24. package/lib/esm/src/components/c3-navigation/c3-navigation-sidebar/components.js +1 -0
  25. package/lib/esm/src/components/c3-navigation/c3-navigation.js +37 -10
  26. package/lib/esm/src/components/c3-navigation/c3-navigation.types.d.ts +5 -2
  27. package/lib/esm/src/components/c3-navigation/c3-notification-provider/c3-notification-provider.js +8 -6
  28. package/lib/esm/src/components/c3-navigation/{c3-navigation-sidebar → c3-org-sidebar}/c3-org-sidebar.d.ts +1 -1
  29. package/lib/esm/src/components/c3-navigation/c3-org-sidebar/c3-org-sidebar.js +125 -0
  30. package/lib/esm/src/components/c3-navigation/c3-org-sidebar/components.d.ts +24 -0
  31. package/lib/esm/src/components/c3-navigation/c3-org-sidebar/components.js +64 -0
  32. package/lib/esm/src/components/c3-navigation/helpers.d.ts +7 -1
  33. package/lib/esm/src/components/c3-navigation/helpers.js +1 -1
  34. package/lib/esm/src/components/c3-navigation/stories/story-helpers.d.ts +3 -1
  35. package/lib/esm/src/components/c3-navigation/stories/story-helpers.js +8 -9
  36. package/lib/esm/src/components/c3-onboarding-survey/c3-onboarding-survey.js +3 -2
  37. package/lib/esm/src/components/c3-onboarding-survey/elements/radioGroupSingle.js +7 -5
  38. package/lib/esm/src/components/c3-onboarding-survey/onboardingModal.d.ts +0 -1
  39. package/lib/esm/src/components/c3-onboarding-survey/onboardingModal.js +4 -3
  40. package/lib/esm/src/components/c3-user-configuration/c3-profile-provider/c3-profile-provider.d.ts +1 -0
  41. package/lib/esm/src/components/c3-user-configuration/c3-profile-provider/c3-profile-provider.js +12 -4
  42. package/lib/esm/src/utils/camunda.types.d.ts +13 -8
  43. package/package.json +17 -17
  44. package/lib/esm/src/components/c3-navigation/c3-navigation-sidebar/c3-org-sidebar.js +0 -85
@@ -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.6.3-rc.4",
7
+ "version": "0.6.4",
8
8
  "scripts": {
9
9
  "clean": "rimraf lib/",
10
10
  "build": "yarn clean && tsc",
@@ -30,29 +30,29 @@
30
30
  "test": "yarn test:ts && yarn test:storybook && yarn test:visual-regression:docker"
31
31
  },
32
32
  "devDependencies": {
33
- "@babel/core": "7.24.4",
34
- "@babel/preset-env": "7.24.4",
33
+ "@babel/core": "7.24.5",
34
+ "@babel/preset-env": "7.24.5",
35
35
  "@babel/preset-react": "7.24.1",
36
36
  "@babel/preset-typescript": "7.24.1",
37
- "@carbon/react": "1.54.0",
37
+ "@carbon/react": "1.55.0",
38
38
  "@mdx-js/react": "3.0.1",
39
39
  "@playwright/test": "1.42.1",
40
40
  "@semantic-release/changelog": "6.0.3",
41
41
  "@semantic-release/git": "10.0.1",
42
- "@storybook/addon-a11y": "8.0.9",
43
- "@storybook/addon-actions": "8.0.9",
44
- "@storybook/addon-docs": "8.0.9",
45
- "@storybook/addon-essentials": "8.0.9",
46
- "@storybook/addon-interactions": "8.0.9",
47
- "@storybook/addon-links": "8.0.9",
48
- "@storybook/addon-mdx-gfm": "8.0.9",
42
+ "@storybook/addon-a11y": "8.0.10",
43
+ "@storybook/addon-actions": "8.0.10",
44
+ "@storybook/addon-docs": "8.0.10",
45
+ "@storybook/addon-essentials": "8.0.10",
46
+ "@storybook/addon-interactions": "8.0.10",
47
+ "@storybook/addon-links": "8.0.10",
48
+ "@storybook/addon-mdx-gfm": "8.0.10",
49
49
  "@storybook/addon-webpack5-compiler-babel": "3.0.3",
50
- "@storybook/blocks": "8.0.9",
50
+ "@storybook/blocks": "8.0.10",
51
51
  "@storybook/preset-scss": "1.0.3",
52
- "@storybook/react": "8.0.9",
53
- "@storybook/react-webpack5": "8.0.9",
54
- "@storybook/test": "8.0.9",
55
- "@storybook/test-runner": "0.17.0",
52
+ "@storybook/react": "8.0.10",
53
+ "@storybook/react-webpack5": "8.0.10",
54
+ "@storybook/test": "8.0.10",
55
+ "@storybook/test-runner": "0.18.0",
56
56
  "@types/carbon-components-react": "7.55.10",
57
57
  "@types/event-source-polyfill": "1.0.5",
58
58
  "@types/mixpanel-browser": "2.49.0",
@@ -86,7 +86,7 @@
86
86
  "sass-loader": "14.1.1",
87
87
  "semantic-release": "23.0.7",
88
88
  "serve": "14.2.1",
89
- "storybook": "8.0.9",
89
+ "storybook": "8.0.10",
90
90
  "style-loader": "4.0.0",
91
91
  "styled-components": "6.1.8",
92
92
  "typescript": "5.4.4",
@@ -19,4 +19,10 @@ export interface RequestPayload {
19
19
  };
20
20
  enableLogs?: boolean;
21
21
  }
22
- export declare function request(payload: RequestPayload): Promise<any>;
22
+ export type RequestResponse<R = undefined> = {
23
+ success: boolean;
24
+ result?: R;
25
+ status?: number;
26
+ error?: string;
27
+ };
28
+ export declare const request: <R = undefined>(payload: RequestPayload) => Promise<RequestResponse<R>>;
@@ -1,6 +1,6 @@
1
1
  import { getEndpoint, NOTIFICATIONS, ACCOUNTS, } from "./endpoints.const";
2
2
  import { JWTUtils } from "./jwt.utils";
3
- export async function request(payload) {
3
+ export const request = async (payload) => {
4
4
  const headers = {};
5
5
  if (payload.camundaAuth) {
6
6
  if (JWTUtils.isExpired(payload.camundaAuth.token) &&
@@ -55,28 +55,32 @@ export async function request(payload) {
55
55
  headers,
56
56
  body,
57
57
  });
58
- let success = true;
59
- if (response.status >= 400 && response.status < 500) {
60
- success = false;
61
- }
62
- if (response.status >= 500) {
63
- success = false;
64
- }
65
- if (!success && payload.enableLogs) {
66
- console.error(response.statusText, response.status);
58
+ if (response.status >= 400) {
59
+ if (payload.enableLogs)
60
+ console.error(response.statusText, response.status);
61
+ return {
62
+ success: false,
63
+ status: response.status,
64
+ error: response.statusText,
65
+ };
67
66
  }
68
67
  const responseType = payload.responseType ?? type;
68
+ let res;
69
69
  switch (responseType) {
70
70
  case "json":
71
- return response.json();
71
+ res = await response.json();
72
+ break;
72
73
  case "text":
73
- return response.text();
74
+ res = await response.text();
75
+ break;
74
76
  default:
75
- return response;
77
+ res = response;
76
78
  }
79
+ return { success: true, result: res };
77
80
  }
78
81
  catch (error) {
79
82
  if (payload.enableLogs)
80
83
  console.error("API request failed:", error);
84
+ return { success: false, error: error?.toString() };
81
85
  }
82
- }
86
+ };
@@ -1,8 +1,8 @@
1
1
  import { HelpCenterConfig } from "../components/c3-help-center/defaultHelpCenterConfig";
2
2
  import { Persona, TileConfig, WpCardType } from "../components/c3-help-center/c3-help-center.types";
3
3
  import { OnboardingConfig } from "../components/c3-onboarding-survey/defaultOnboardingConfig";
4
- import { RequestPayload } from "./api";
5
- export declare const getConfig: (accessToken: string, audience: string, orgId: string) => Promise<HelpCenterConfig | null>;
4
+ import { RequestPayload, RequestResponse } from "./api";
5
+ export declare const getConfig: (accessToken: string, audience: string, orgId: string) => Promise<RequestResponse<HelpCenterConfig | null>>;
6
6
  export declare const getTiles: ({ accessToken, tileConfig, salesPlanType, clusterIds, persona, flags, cloudAudience, }: {
7
7
  accessToken: string;
8
8
  tileConfig: TileConfig[];
@@ -13,19 +13,19 @@ export declare const getTiles: ({ accessToken, tileConfig, salesPlanType, cluste
13
13
  clusterIds: string[];
14
14
  salesPlanType: string;
15
15
  flags: string[];
16
- }) => Promise<WpCardType[]>;
16
+ }) => Promise<RequestResponse<WpCardType[]>>;
17
17
  export declare const getOnboardingConfig: ({ camundaAuth, audience, orgId, }: {
18
18
  audience: string;
19
19
  camundaAuth: RequestPayload["camundaAuth"];
20
20
  orgId: string;
21
- }) => Promise<OnboardingConfig>;
21
+ }) => Promise<RequestResponse<OnboardingConfig>>;
22
22
  export declare const updatePersona: ({ newPersona, audience, accessToken, orgId, userId, }: {
23
23
  newPersona: Persona;
24
24
  audience: string;
25
25
  orgId: string;
26
26
  userId: string;
27
27
  accessToken: string;
28
- }) => Promise<void>;
28
+ }) => Promise<RequestResponse<undefined>>;
29
29
  export declare const submitSurvey: ({ audience, token, data, }: {
30
30
  audience: string;
31
31
  token: string;
@@ -33,9 +33,9 @@ export declare const submitSurvey: ({ audience, token, data, }: {
33
33
  email: string;
34
34
  orgUuid: string;
35
35
  };
36
- }) => Promise<void>;
36
+ }) => Promise<RequestResponse<undefined>>;
37
37
  export declare const submitFeedback: ({ token, audience, formData, }: {
38
38
  token: string;
39
39
  audience: string;
40
40
  formData: FormData;
41
- }) => Promise<any>;
41
+ }) => Promise<RequestResponse<undefined>>;
@@ -1,4 +1,5 @@
1
1
  import { C3NotificationsProps } from "../components/c3-navigation/c3-navigation.types";
2
+ import { RequestResponse } from "./api";
2
3
  export interface Notification {
3
4
  uuid: string;
4
5
  userId?: string;
@@ -25,7 +26,7 @@ export interface Notification {
25
26
  }
26
27
  export type AnalyticsEvent = "notification-panel-opened" | "notification-clicked-cta";
27
28
  export declare class NotificationService {
28
- static getNotifications(options: C3NotificationsProps): Promise<Notification[]>;
29
+ static getNotifications(options: C3NotificationsProps): Promise<RequestResponse<Notification[]>>;
29
30
  static sendAnalyticsEvent(options: C3NotificationsProps, eventOptions: {
30
31
  event: AnalyticsEvent;
31
32
  id?: string;
@@ -1,3 +1,4 @@
1
+ import { RequestResponse } from "./api";
1
2
  export type StartingPrice = {
2
3
  amount: number;
3
4
  currency: string;
@@ -6,4 +7,9 @@ export type StartingPrice = {
6
7
  export declare const getStartingPrice: ({ token, audience, }: {
7
8
  token: string;
8
9
  audience: string;
9
- }) => Promise<StartingPrice>;
10
+ }) => Promise<RequestResponse<StartingPrice>>;
11
+ export declare const leaveOrganization: ({ token, audience, orgId, }: {
12
+ token: string;
13
+ audience: string;
14
+ orgId: string;
15
+ }) => Promise<RequestResponse>;
@@ -4,3 +4,8 @@ export const getStartingPrice = async ({ token, audience, }) => request({
4
4
  camundaAuth: { token },
5
5
  responseType: "json",
6
6
  });
7
+ export const leaveOrganization = async ({ token, audience, orgId, }) => request({
8
+ url: `https://accounts.${audience}/external/organizations/${orgId}/membership`,
9
+ camundaAuth: { token },
10
+ method: "delete",
11
+ });
@@ -1,3 +1,4 @@
1
+ import { RequestResponse } from "./api";
1
2
  import { C3NotificationsProps } from "../components/c3-navigation/c3-navigation.types";
2
3
  import { Theme } from "../components/c3-user-configuration/c3-profile-provider/c3-profile-provider";
3
4
  import { Organization } from "../utils/camunda.types";
@@ -16,5 +17,5 @@ export type UpdateThemeOptions = C3NotificationsProps & {
16
17
  theme: Profile["theme"];
17
18
  };
18
19
  export declare const updateTheme: ({ endpoints, stage, userToken, getNewUserToken, theme, }: UpdateThemeOptions) => Promise<void>;
19
- export declare const getOrgs: (stage: string, accessToken: string) => Promise<Organization[] | null>;
20
- export declare const getClusters: (stage: string, accessToken: string, orgId: string) => Promise<Cluster[] | null>;
20
+ export declare const getOrgs: (stage: string, accessToken: string) => Promise<RequestResponse<Organization[] | null>>;
21
+ export declare const getClusters: (stage: string, accessToken: string, orgId: string) => Promise<RequestResponse<Cluster[] | null>>;
@@ -15,12 +15,12 @@ export const C3AppTeaserPage = ({ appName, redirectToClusters, redirectToCreateC
15
15
  if (!userToken || !decodedAudience)
16
16
  return;
17
17
  (async () => {
18
- const res = await getStartingPrice({
18
+ const { result } = await getStartingPrice({
19
19
  token: userToken,
20
20
  audience: decodedAudience,
21
21
  });
22
- if (res) {
23
- setPricing(res);
22
+ if (result) {
23
+ setPricing(result);
24
24
  }
25
25
  })();
26
26
  }, [userToken, decodedAudience]);
@@ -12,7 +12,7 @@ export const C3EmptyState = ({ icon, heading, description, button, link, }) => (
12
12
  React.createElement(Stack, { gap: 6 },
13
13
  React.createElement("p", { style: { maxWidth: "400px" } }, description),
14
14
  React.createElement(Stack, { gap: 5 },
15
- button && (React.createElement(React.Fragment, null, "items" in button ? (React.createElement(MenuButton, { size: "md", disabled: button.disabled, label: button.label }, button.items.map((menuItem) => {
15
+ button && (React.createElement(React.Fragment, null, "items" in button ? (React.createElement(MenuButton, { size: "md", disabled: button.disabled, label: button.label, menuAlignment: "bottom" }, button.items.map((menuItem) => {
16
16
  return (React.createElement(MenuItem, { key: menuItem.id, onClick: menuItem.onClick, renderIcon: menuItem.icon, disabled: menuItem.disabled, label: menuItem.label }));
17
17
  }))) : (React.createElement(Button, { id: button.id, size: "md", onClick: button.onClick, renderIcon: button.icon, disabled: button.disabled }, button.label)))),
18
18
  link && (React.createElement("div", null,
@@ -60,7 +60,7 @@ export const C3HelpCenter = ({ autoStartSurvey, origin, flags, onRequestClose, m
60
60
  const fetchConfig = async () => {
61
61
  if (!userToken || !decodedAudience)
62
62
  return;
63
- const onboardConfig = await getConfig(userToken, decodedAudience, activeOrganizationId);
63
+ const { result: onboardConfig } = await getConfig(userToken, decodedAudience, activeOrganizationId);
64
64
  setHelpCenterConfig(onboardConfig || defaultHelpCenterConfig);
65
65
  };
66
66
  const isFirstLoad = useRef(true);
@@ -9,6 +9,17 @@ import { useC3HelpCenter } from "./c3-help-center-provider";
9
9
  import { useC3Profile } from "../c3-user-configuration/c3-profile-provider/c3-profile-provider";
10
10
  import { TabContentSkeleton } from "./tabs/tabContentSkeleton";
11
11
  import { StyledModalBody, StyledModalHeader } from "./styles";
12
+ import styled from "styled-components";
13
+ const StyledModalFooter = styled(ModalFooter) `
14
+ height: 62px;
15
+ padding-right: 16px;
16
+ padding-top: 16px;
17
+ padding-bottom: 16px;
18
+ border-top: 1px;
19
+ border-style: solid;
20
+ border-color: ${({ $hcTheme }) => $hcTheme === "light" ? "#E0E0E0" : "#727272"};
21
+ background-color: ${({ $hcTheme }) => $hcTheme === "light" ? "#FFFFFF" : "#161616"};
22
+ `;
12
23
  export const HelpCenter = ({ configuration, persona, email, audience, flags = [], onRequestResumeSurvey, onRequestRetakeSurvey, onRequestClose, mixpanelTrack, theme, origin, initialTab, }) => {
13
24
  const { tabs } = configuration;
14
25
  const firstTab = tabs[0].id;
@@ -29,7 +40,7 @@ export const HelpCenter = ({ configuration, persona, email, audience, flags = []
29
40
  setIsLoadingTiles(true);
30
41
  for (const singleTab of tabs) {
31
42
  if (token) {
32
- tiles[singleTab.id] = await getTiles({
43
+ const { result } = await getTiles({
33
44
  tileConfig: singleTab.tiles,
34
45
  cloudAudience: audience,
35
46
  persona,
@@ -38,6 +49,8 @@ export const HelpCenter = ({ configuration, persona, email, audience, flags = []
38
49
  flags,
39
50
  accessToken: token,
40
51
  });
52
+ if (result)
53
+ tiles[singleTab.id] = result;
41
54
  }
42
55
  }
43
56
  setIsLoadingTiles(false);
@@ -181,23 +194,17 @@ export const HelpCenter = ({ configuration, persona, email, audience, flags = []
181
194
  }, "aria-label": text }, text)));
182
195
  })))),
183
196
  React.createElement("li", { style: { position: "absolute", bottom: "20px" } },
184
- React.createElement("ul", null, configuration.links.map((link) => (React.createElement(SideNavMenuItem, { key: link.label.split(" ").join("-").toLowerCase(), href: link.link, target: "_blank" },
197
+ React.createElement("ul", null, configuration.links.map((link) => (React.createElement(SideNavMenuItem, { key: link.label.split(" ").join("-").toLowerCase(), href: link.link,
198
+ // eslint-disable-next-line
199
+ // @ts-ignore
200
+ target: "_blank" },
185
201
  React.createElement("span", { className: "cds--link" }, link.label)))))))),
186
202
  content,
187
203
  React.createElement("div", { style: { display: activeTab === "feedback" ? "block" : "none" } },
188
204
  React.createElement(Feedback, { audience: audience, theme: theme, mixpanelTrack: mixpanelTrack, setHeader: (head) => {
189
205
  header = head;
190
206
  }, salesPlanType: organization?.salesPlan?.type ?? "" })))),
191
- persona.complete && activeTab === "recommendations" && (React.createElement(ModalFooter, { style: {
192
- height: "62px",
193
- paddingRight: "16px",
194
- paddingTop: "16px",
195
- paddingBottom: "16px",
196
- borderTop: "1px",
197
- borderStyle: "solid",
198
- borderColor: theme === "light" ? "#E0E0E0" : "#727272",
199
- backgroundColor: theme === "light" ? "#FFFFFF" : "#161616",
200
- } },
207
+ persona.complete && activeTab === "recommendations" && (React.createElement(StyledModalFooter, { "$hcTheme": theme },
201
208
  React.createElement("div", null,
202
209
  React.createElement(Button, { kind: "tertiary", renderIcon: Undo, onClick: onRequestRetakeSurvey, size: "sm", style: {
203
210
  maxWidth: "200px",
@@ -1,4 +1,3 @@
1
- /// <reference path="../../../../../src/carbon.d.ts" />
2
1
  import { ModalBodyProps, ModalHeaderProps } from "@carbon/react";
3
2
  import { FC } from "react";
4
3
  export declare const headingStyles: import("styled-components").RuleSet<object>;
@@ -3,6 +3,7 @@ import React, { useState } from "react";
3
3
  import { Idea, Debug, Information, Chat } from "@carbon/react/icons";
4
4
  import { submitFeedback } from "../../../api/help-center";
5
5
  import { useC3UserConfiguration } from "../../c3-user-configuration/c3-user-configuration-provider";
6
+ import styled from "styled-components";
6
7
  var ReportType;
7
8
  (function (ReportType) {
8
9
  ReportType["Feedback"] = "feedback";
@@ -21,6 +22,9 @@ var Placeholder;
21
22
  Placeholder["Idea"] = "Tell us how we can improve our product";
22
23
  Placeholder["Bug"] = "Tell us what went wrong";
23
24
  })(Placeholder || (Placeholder = {}));
25
+ const StyledRadioTile = styled(RadioTile) `
26
+ min-width: 200px;
27
+ `;
24
28
  export const Feedback = (props) => {
25
29
  props.setHeader("Share your feedback");
26
30
  const { userToken } = useC3UserConfiguration();
@@ -121,23 +125,17 @@ export const Feedback = (props) => {
121
125
  columnGap: "12px",
122
126
  } },
123
127
  React.createElement("div", { style: { flexGrow: "1" } },
124
- React.createElement(RadioTile, { checked: selectedType === ReportType.Feedback, onClick: () => {
125
- setSelectedType(ReportType.Feedback);
126
- }, value: ReportType.Feedback, style: { minWidth: "200px" } },
128
+ React.createElement(StyledRadioTile, { checked: selectedType === ReportType.Feedback, onChange: (value) => setSelectedType(value), value: ReportType.Feedback },
127
129
  React.createElement(Stack, null,
128
130
  React.createElement(Chat, { size: "40" }),
129
131
  React.createElement("p", null, "General feedback")))),
130
132
  React.createElement("div", { style: { flexGrow: "1" } },
131
- React.createElement(RadioTile, { checked: selectedType === ReportType.Idea, onClick: () => {
132
- setSelectedType(ReportType.Idea);
133
- }, value: ReportType.Idea, style: { minWidth: "200px" } },
133
+ React.createElement(StyledRadioTile, { checked: selectedType === ReportType.Idea, onChange: (value) => setSelectedType(value), value: ReportType.Idea },
134
134
  React.createElement(Stack, null,
135
135
  React.createElement(Idea, { size: "40" }),
136
136
  React.createElement("p", null, "Suggest an idea")))),
137
137
  React.createElement("div", { style: { flexGrow: "1" } },
138
- React.createElement(RadioTile, { checked: selectedType === ReportType.Bug, onClick: () => {
139
- setSelectedType(ReportType.Bug);
140
- }, value: ReportType.Bug, style: { minWidth: "200px" } },
138
+ React.createElement(StyledRadioTile, { checked: selectedType === ReportType.Bug, onChange: (value) => setSelectedType(value), value: ReportType.Bug },
141
139
  React.createElement(Stack, null,
142
140
  React.createElement(Debug, { size: "40" }),
143
141
  React.createElement("p", null, "Report a bug"))))))),
@@ -11,7 +11,7 @@ export const C3NavigationAppBar = ({ app: appProps, appBar, forwardRef, navbar,
11
11
  const { currentApp, domain, analyticsTrack, currentClusterUuid } = useC3UserConfiguration();
12
12
  const { clusters, activeOrg, isEnabled } = useC3Profile();
13
13
  const [appBarOpen, setAppBarOpen] = useState(appBar.isOpen);
14
- const [panelRef, iconRef] = useOnClickOutside(() => setAppBarOpen(false));
14
+ const { setPanelRef: panelRef, setIconRef: iconRef } = useOnClickOutside(() => setAppBarOpen(false));
15
15
  const [appElements, setAppElements] = useState([]);
16
16
  if (!appBar.elements && !isEnabled)
17
17
  console.warn("No app elements and user config provided. Please provide at least one of them.");
@@ -79,7 +79,13 @@ export const C3NavigationAppBar = ({ app: appProps, appBar, forwardRef, navbar,
79
79
  }, [JSON.stringify(clusters), currentApp, domain]);
80
80
  const appBarElements = appBar.elements || (clusters ? appElements : null);
81
81
  return (React.createElement(React.Fragment, null,
82
- React.createElement(HeaderGlobalAction, { ref: iconRef, "aria-label": "Camunda components", isActive: appBarOpen, onClick: () => {
82
+ React.createElement(HeaderGlobalAction
83
+ // eslint-disable-next-line
84
+ // @ts-ignore
85
+ , {
86
+ // eslint-disable-next-line
87
+ // @ts-ignore
88
+ ref: iconRef, "aria-label": "Camunda components", isActive: appBarOpen, onClick: () => {
83
89
  setAppBarOpen(!appBarOpen);
84
90
  }, tooltipAlignment: "start",
85
91
  /* eslint-disable-next-line @typescript-eslint/ban-ts-comment */
@@ -7,5 +7,6 @@ declare const C3NavigationSidebarElement: (props: {
7
7
  itemTabIndex?: number;
8
8
  sideBar: C3NavigationSideBarProps;
9
9
  setSideBarOpen: (open: boolean) => void;
10
+ scrollBarWidth: number;
10
11
  }) => React.JSX.Element;
11
12
  export default C3NavigationSidebarElement;
@@ -1,34 +1,62 @@
1
1
  import { Button } from "@carbon/react";
2
2
  import React, { useEffect, useRef, useState } from "react";
3
3
  import { SwitcherDivider } from "./components";
4
+ import styled from "styled-components";
5
+ const Row = styled.div `
6
+ display: flex;
7
+ justify-content: start;
8
+ align-items: center;
9
+
10
+ .cds--switcher__item:nth-child(1) {
11
+ margin-block-start: 0;
12
+ }
13
+
14
+ &:nth-child(1) {
15
+ margin-block-start: 1rem;
16
+ }
17
+
18
+ .cds--overflow-menu-options {
19
+ z-index: 9000 !important;
20
+ }
21
+ `;
4
22
  const C3NavigationSidebarElement = (props) => {
5
23
  const sideBarElementRef = useRef(null);
6
24
  const [isOverflown, setIsOverflown] = useState(false);
7
- useEffect(() => {
25
+ const { overflowMenu } = props.element;
26
+ const handleSetIsOverflown = () => {
8
27
  const element = sideBarElementRef.current;
9
28
  setIsOverflown(element ? element.offsetWidth < element.scrollWidth : false);
10
- }, [JSON.stringify(props.element)]);
29
+ };
30
+ useEffect(() => {
31
+ window.addEventListener("resize", handleSetIsOverflown);
32
+ handleSetIsOverflown();
33
+ return () => window.removeEventListener("resize", handleSetIsOverflown);
34
+ }, []);
11
35
  return (React.createElement(React.Fragment, null,
12
36
  props.element.preceedingDivider && React.createElement(SwitcherDivider, null),
13
- React.createElement(Button, { style: {
14
- width: "calc(16rem - 2px)",
15
- ...(props.index === 0 &&
16
- (!("elements" in props.sideBar) || !props.sideBar.elements)
17
- ? { marginTop: "1.5rem" }
18
- : {}),
19
- }, size: "sm", kind: props.element.kind ?? "ghost", className: "cds--switcher__item", onClick: () => {
20
- if (props.element.onClick) {
21
- props.element.onClick();
22
- }
23
- if (props.sideBar.closeOnClick !== false) {
24
- props.setSideBarOpen(false);
25
- }
26
- }, tabIndex: props.itemTabIndex, renderIcon: props.element.renderIcon },
27
- React.createElement("span", { ref: (el) => (sideBarElementRef.current = el), title: isOverflown ? props.element.label : "", style: {
28
- overflow: "hidden",
29
- textOverflow: "ellipsis",
30
- whiteSpace: "nowrap",
31
- width: "100%",
32
- } }, props.element.label))));
37
+ React.createElement(Row, null,
38
+ React.createElement(Button, { style: {
39
+ width: overflowMenu
40
+ ? `calc(14rem - ${props.scrollBarWidth}px)`
41
+ : `calc(16rem - ${props.scrollBarWidth}px)`,
42
+ ...(props.index === 0 &&
43
+ (!("elements" in props.sideBar) || !props.sideBar.elements)
44
+ ? { marginTop: "1.5rem" }
45
+ : {}),
46
+ }, size: "sm", kind: props.element.kind ?? "ghost", className: "cds--switcher__item", onClick: () => {
47
+ if (props.element.onClick) {
48
+ props.element.onClick();
49
+ }
50
+ if (props.sideBar.closeOnClick !== false) {
51
+ props.setSideBarOpen(false);
52
+ }
53
+ }, tabIndex: props.itemTabIndex, renderIcon: props.element.renderIcon },
54
+ React.createElement("span", { ref: sideBarElementRef, title: isOverflown ? props.element.label : "", style: {
55
+ overflow: "hidden",
56
+ textOverflow: "ellipsis",
57
+ whiteSpace: "nowrap",
58
+ width: "100%",
59
+ } }, props.element.label)),
60
+ overflowMenu)));
33
61
  };
34
62
  export default C3NavigationSidebarElement;
@@ -1,5 +1,5 @@
1
1
  import { Button, HeaderGlobalAction, HeaderPanel as CarbonHeaderPanel, Stack, SwitcherDivider, } from "@carbon/react";
2
- import React from "react";
2
+ import React, { useEffect } from "react";
3
3
  import { useOnClickOutside } from "../helpers";
4
4
  import C3NavigationSidebarElement from "./c3-navigation-sidebar-element";
5
5
  import styled from "styled-components";
@@ -23,7 +23,7 @@ const BottomElements = styled.div `
23
23
  const C3NavigationSideBar = (props) => {
24
24
  const { icon, sideBar, children, version, bottomChildren } = props;
25
25
  const { callbacks, onOpen } = sideBar;
26
- const { isOpen, setIsOpen: setOpenState } = useSidebarState()[sideBar.type];
26
+ const { isOpen, setIsOpen: setOpenState, scrollBarWidth, setScrollBarWidth, } = useSidebarState()[sideBar.type];
27
27
  const setIsOpen = (open) => {
28
28
  if (open) {
29
29
  callbacks?.beforeOpening?.();
@@ -34,16 +34,46 @@ const C3NavigationSideBar = (props) => {
34
34
  callbacks?.afterClosing?.();
35
35
  };
36
36
  const itemTabIndex = isOpen ? undefined : -1;
37
- const [panelRef, iconRef] = useOnClickOutside(() => setIsOpen(false));
37
+ const { panelRef, setPanelRef, setIconRef } = useOnClickOutside(() => setIsOpen(false));
38
38
  const id = `c3-${sideBar.type}-sidebar`;
39
+ const handleResize = () => {
40
+ const scrollbarWidth = panelRef.current
41
+ ? panelRef.current?.offsetWidth - panelRef.current?.clientWidth
42
+ : 0;
43
+ setScrollBarWidth(scrollbarWidth);
44
+ };
45
+ useEffect(() => {
46
+ window.addEventListener("resize", handleResize);
47
+ handleResize();
48
+ return () => window.removeEventListener("resize", handleResize);
49
+ }, []);
50
+ useEffect(() => {
51
+ if (isOpen) {
52
+ setTimeout(() => {
53
+ handleResize();
54
+ }, 120);
55
+ }
56
+ }, [isOpen]);
39
57
  return (React.createElement(Wrapper, null,
40
- React.createElement(HeaderGlobalAction, { ref: iconRef, "aria-label": `Open ${sideBar.ariaLabel}`, "aria-expanded": isOpen, "aria-controls": id, onClick: () => {
58
+ React.createElement(HeaderGlobalAction
59
+ // eslint-disable-next-line
60
+ // @ts-ignore
61
+ , {
62
+ // eslint-disable-next-line
63
+ // @ts-ignore
64
+ ref: setIconRef, "aria-label": `Open ${sideBar.ariaLabel}`, "aria-expanded": isOpen, "aria-controls": id, onClick: () => {
41
65
  setIsOpen(!isOpen);
42
66
  }, isActive: isOpen, tooltipAlignment: sideBar.type === "user" ? "end" : "center",
43
67
  /* eslint-disable-next-line @typescript-eslint/ban-ts-comment */
44
68
  /* @ts-ignore */
45
69
  leaveDelayMs: 100 }, icon),
46
- React.createElement(HeaderPanel, { ref: panelRef, expanded: isOpen, id: id },
70
+ React.createElement(HeaderPanel
71
+ // eslint-disable-next-line
72
+ // @ts-ignore
73
+ , {
74
+ // eslint-disable-next-line
75
+ // @ts-ignore
76
+ ref: setPanelRef, expanded: isOpen, id: id, style: { width: isOpen ? "calc(16rem)" : "0" } },
47
77
  React.createElement(Stack, null,
48
78
  children,
49
79
  sideBar.elements &&
@@ -52,7 +82,7 @@ const C3NavigationSideBar = (props) => {
52
82
  sideBar.customElements &&
53
83
  "activeOrganization" in sideBar.customElements &&
54
84
  !sideBar.customElements?.activeOrganization && React.createElement(SwitcherDivider, null),
55
- sideBar.elements?.map((element, index) => (React.createElement(C3NavigationSidebarElement, { key: element.key, element: element, index: index, sideBar: sideBar, setSideBarOpen: setIsOpen, itemTabIndex: itemTabIndex }))),
85
+ sideBar.elements?.map((element, index) => (React.createElement(C3NavigationSidebarElement, { key: element.key, element: element, index: index, sideBar: sideBar, setSideBarOpen: setIsOpen, itemTabIndex: itemTabIndex, scrollBarWidth: scrollBarWidth }))),
56
86
  bottomChildren),
57
87
  version,
58
88
  React.createElement(BottomElements, null, sideBar.bottomElements &&
@@ -63,6 +93,6 @@ const C3NavigationSideBar = (props) => {
63
93
  if (sideBar.closeOnClick !== false) {
64
94
  setIsOpen(false);
65
95
  }
66
- }, tabIndex: itemTabIndex }, element.label)))))));
96
+ }, tabIndex: itemTabIndex, style: { width: `calc(16rem + 2px - ${scrollBarWidth}px)` } }, element.label)))))));
67
97
  };
68
98
  export default C3NavigationSideBar;
@@ -25,6 +25,7 @@ export type C3NavigationOrgSideBarProps = C3NavigationSideBarBaseProps & {
25
25
  activeOrganization?: CamundaOrg;
26
26
  };
27
27
  switchToOrg?: (orgId: string) => void;
28
+ manageOrg?: (orgId: string) => void;
28
29
  };
29
30
  export type C3NavigationInfoSideBarProps = C3NavigationSideBarBaseProps & {
30
31
  type: "info";
@@ -45,7 +45,7 @@ export const C3NotificationSidebar = ({ sideBar }) => {
45
45
  const { onLinkClick } = sideBar;
46
46
  const { notifications, markAsRead, dismiss, markAllAsRead, dismissAll, analytics, enabled, } = useContext(C3NotificationContext);
47
47
  const [unreadNotifications, setUnreadNotifications] = useState([]);
48
- const hasUnreadNotifications = notifications.some(({ state }) => state === "new");
48
+ const hasUnreadNotifications = notifications?.some(({ state }) => state === "new");
49
49
  const { isOpen } = useNotificationSidebarState();
50
50
  const notificationsRef = useRef();
51
51
  notificationsRef.current = notifications;
@@ -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, label: "Notifications" })) },
89
+ }, icon: hasUnreadNotifications ? (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 && (
@@ -8,6 +8,8 @@ type DefaultValues = {
8
8
  type SideBarState = {
9
9
  isOpen: boolean;
10
10
  setIsOpen: (isOpen: boolean) => void;
11
+ scrollBarWidth: number;
12
+ setScrollBarWidth: (scrollBarWidth: number) => void;
11
13
  };
12
14
  type C3SidebarsState = {
13
15
  notifications: SideBarState;