@camunda/camunda-composite-components 0.1.1 → 0.1.2-rc.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 (70) hide show
  1. package/README.md +60 -0
  2. package/lib/esm/api/api.d.ts +19 -19
  3. package/lib/esm/api/api.js +67 -65
  4. package/lib/esm/api/endpoints.const.d.ts +12 -12
  5. package/lib/esm/api/endpoints.const.js +25 -24
  6. package/lib/esm/api/jwt.utils.d.ts +3 -3
  7. package/lib/esm/api/jwt.utils.js +21 -23
  8. package/lib/esm/api/notifications.d.ts +35 -64
  9. package/lib/esm/api/notifications.js +159 -168
  10. package/lib/esm/components/c3-empty-state/c3-empty-state.d.ts +2 -8
  11. package/lib/esm/components/c3-empty-state/c3-empty-state.js +17 -58
  12. package/lib/esm/components/c3-empty-state/c3-empty-state.test.d.ts +1 -0
  13. package/lib/esm/components/c3-empty-state/c3-empty-state.test.js +12 -0
  14. package/lib/esm/components/c3-empty-state/c3-empty-state.types.d.ts +19 -19
  15. package/lib/esm/components/c3-empty-state/c3-empty-state.types.js +1 -1
  16. package/lib/esm/components/c3-navigation/c3-info-button.d.ts +3 -3
  17. package/lib/esm/components/c3-navigation/c3-info-button.js +5 -13
  18. package/lib/esm/components/c3-navigation/c3-navigation-actions/c3-action-buttons.d.ts +5 -5
  19. package/lib/esm/components/c3-navigation/c3-navigation-actions/c3-action-buttons.js +13 -21
  20. package/lib/esm/components/c3-navigation/c3-navigation-actions/c3-action-buttons.types.d.ts +6 -5
  21. package/lib/esm/components/c3-navigation/c3-navigation-actions/c3-action-buttons.types.js +1 -1
  22. package/lib/esm/components/c3-navigation/c3-navigation-appbar.d.ts +3 -3
  23. package/lib/esm/components/c3-navigation/c3-navigation-appbar.js +68 -157
  24. package/lib/esm/components/c3-navigation/c3-navigation-sidebar/c3-info-sidebar.d.ts +5 -5
  25. package/lib/esm/components/c3-navigation/c3-navigation-sidebar/c3-info-sidebar.js +39 -62
  26. package/lib/esm/components/c3-navigation/c3-navigation-sidebar/c3-navigation-sidebar-element.d.ts +9 -9
  27. package/lib/esm/components/c3-navigation/c3-navigation-sidebar/c3-navigation-sidebar-element.js +33 -56
  28. package/lib/esm/components/c3-navigation/c3-navigation-sidebar/c3-navigation-sidebar.d.ts +9 -9
  29. package/lib/esm/components/c3-navigation/c3-navigation-sidebar/c3-navigation-sidebar.js +57 -110
  30. package/lib/esm/components/c3-navigation/c3-navigation-sidebar/c3-navigation-sidebar.types.d.ts +61 -71
  31. package/lib/esm/components/c3-navigation/c3-navigation-sidebar/c3-navigation-sidebar.types.js +1 -1
  32. package/lib/esm/components/c3-navigation/c3-navigation-sidebar/c3-notification-sidebar.d.ts +4 -4
  33. package/lib/esm/components/c3-navigation/c3-navigation-sidebar/c3-notification-sidebar.js +88 -142
  34. package/lib/esm/components/c3-navigation/c3-navigation-sidebar/c3-org-sidebar.d.ts +5 -5
  35. package/lib/esm/components/c3-navigation/c3-navigation-sidebar/c3-org-sidebar.js +51 -105
  36. package/lib/esm/components/c3-navigation/c3-navigation-sidebar/c3-sidebar-state-provider.d.ts +24 -26
  37. package/lib/esm/components/c3-navigation/c3-navigation-sidebar/c3-sidebar-state-provider.js +25 -38
  38. package/lib/esm/components/c3-navigation/c3-navigation-sidebar/c3-user-sidebar.d.ts +5 -5
  39. package/lib/esm/components/c3-navigation/c3-navigation-sidebar/c3-user-sidebar.js +57 -146
  40. package/lib/esm/components/c3-navigation/c3-navigation-sidebar/components.d.ts +1 -6
  41. package/lib/esm/components/c3-navigation/c3-navigation-sidebar/components.js +4 -4
  42. package/lib/esm/components/c3-navigation/c3-navigation.d.ts +2 -13
  43. package/lib/esm/components/c3-navigation/c3-navigation.js +90 -214
  44. package/lib/esm/components/c3-navigation/c3-navigation.test.d.ts +1 -0
  45. package/lib/esm/components/c3-navigation/c3-navigation.test.js +76 -0
  46. package/lib/esm/components/c3-navigation/c3-navigation.types.d.ts +63 -69
  47. package/lib/esm/components/c3-navigation/c3-navigation.types.js +1 -1
  48. package/lib/esm/components/c3-navigation/c3-notification-provider/c3-notification-container.d.ts +13 -30
  49. package/lib/esm/components/c3-navigation/c3-notification-provider/c3-notification-container.js +70 -114
  50. package/lib/esm/components/c3-navigation/c3-notification-provider/c3-notification-provider.d.ts +27 -29
  51. package/lib/esm/components/c3-navigation/c3-notification-provider/c3-notification-provider.js +90 -118
  52. package/lib/esm/components/c3-navigation/helpers.d.ts +3 -5
  53. package/lib/esm/components/c3-navigation/helpers.js +49 -53
  54. package/lib/esm/components/c3-navigation/index.d.ts +2 -4
  55. package/lib/esm/components/c3-navigation/index.js +3 -3
  56. package/lib/esm/components/c3-navigation/story-helpers.d.ts +18 -23
  57. package/lib/esm/components/c3-navigation/story-helpers.js +197 -200
  58. package/lib/esm/components/c3-navigation/story-templates.d.ts +8 -8
  59. package/lib/esm/components/c3-navigation/story-templates.js +33 -66
  60. package/lib/esm/components/c3-user-configuration/c3-user-configuration-provider.d.ts +16 -20
  61. package/lib/esm/components/c3-user-configuration/c3-user-configuration-provider.js +4 -9
  62. package/lib/esm/components/test-utils.d.ts +3 -0
  63. package/lib/esm/components/test-utils.js +22 -0
  64. package/lib/esm/icons/c3-icons.d.ts +5 -7
  65. package/lib/esm/icons/c3-icons.js +14 -82
  66. package/lib/esm/icons/c3-icons.types.d.ts +1 -1
  67. package/lib/esm/icons/c3-icons.types.js +1 -1
  68. package/lib/esm/index.d.ts +9 -14
  69. package/lib/esm/index.js +4 -4
  70. package/package.json +15 -5
package/README.md CHANGED
@@ -55,3 +55,63 @@ return (
55
55
 
56
56
  - [Console team](https://confluence.camunda.com/display/HAN/Console+Team) started this, their C4 repo can be found [here](https://github.com/camunda-cloud/camunda-cloud-management-apps/tree/main/packages/c4)
57
57
  - [Identity team](https://github.com/camunda/team-identity): [c4-identity](https://github.com/camunda-cloud/c4-identity)
58
+
59
+ ## Testing
60
+
61
+ ### Visual regression tests (VRT)
62
+
63
+ We use [Playwright](https://playwright.dev/docs/intro) screenshot tests to be aware of any visual changes introduced by dependency updates or changes in the component code.
64
+
65
+ #### Running VRT locally
66
+
67
+ We run VRT inside a docker container to avoid different results caused by different platforms. Simply run:
68
+
69
+ ```shell
70
+ yarn start:docker-storybook
71
+ ```
72
+
73
+ then
74
+
75
+ ```shell
76
+ yarn test:visual-regression:docker
77
+ ```
78
+
79
+ The commands above will:
80
+
81
+ 1. Build storybook.
82
+ 2. Start a Playwright docker container with the name `c3-visual-regression`.
83
+ 3. Serve storybook within the docker container.
84
+ 4. Run the visual regression tests within the docker container.
85
+
86
+ When developing, it might not always be helpful to run all of these steps at once. You can find more granular scripts in the [package.json](package.json).
87
+
88
+ #### Running VRT in the CI
89
+
90
+ There is a `Visual regression tests` workflow that is triggered automatically on push. You can also trigger it manually in the `Actions` tab.
91
+
92
+ If the workflow fails, you can find the test report by navigating to the workflow run summary, then scrolling down to the `Artifacts` section.
93
+ Click on the artifact called `Playwright report` to download it, go to your downloads folder, then open the `index.html` file of the test report in your browser to view the report.
94
+
95
+ #### How to deal with failing tests
96
+
97
+ When a VRT fails, this can have two reasons:
98
+
99
+ 1. A change was introduced unknowingly. In this case, have a look at the test report and check if the change was intended. If it is, proceed with 2.
100
+ 2. You made a change to the UI on purpose. In this case you need to update the screenshot as follows.
101
+
102
+ Make sure you have the `c3-visual-regression` docker container running, or start it like described [here](#running-vrt-locally).
103
+ Then, have a look at the test report:
104
+
105
+ ```shell
106
+ yarn report:visual-regression
107
+ ```
108
+
109
+ Double-check that you don't apply any unwanted changes by looking at the difference that is highlighted in the failed test's report.
110
+
111
+ To update all screenshots, run:
112
+
113
+ ```shell
114
+ yarn update:visual-regression:docker
115
+ ```
116
+
117
+ The tests should now pass locally and in the CI. Commit and push the updated screenshot(s).
@@ -1,23 +1,23 @@
1
- import { Endpoints, Stage } from "./endpoints.const"
1
+ import { Endpoints, Stage } from "./endpoints.const";
2
2
  export declare class HttpError extends Error {
3
- status: number
4
- constructor(message: string, status: number)
3
+ status: number;
4
+ constructor(message: string, status: number);
5
5
  }
6
6
  export interface RequestPayload {
7
- base?: "notifications"
8
- stage?: Stage
9
- endpoints?: Endpoints
10
- url: string
11
- method: "get" | "post" | "put" | "delete" | "patch"
12
- headers?: {
13
- [key: string]: string
14
- }
15
- type?: "json" | "text" | "none"
16
- responseType?: "json" | "text" | "none"
17
- camundaAuth?: {
18
- token: string
19
- refreshTokenMethod: () => Promise<string>
20
- }
21
- body?: any
7
+ base?: "notifications";
8
+ stage?: Stage;
9
+ endpoints?: Endpoints;
10
+ url: string;
11
+ method: "get" | "post" | "put" | "delete" | "patch";
12
+ headers?: {
13
+ [key: string]: string;
14
+ };
15
+ type?: "json" | "text" | "none";
16
+ responseType?: "json" | "text" | "none";
17
+ camundaAuth?: {
18
+ token: string;
19
+ refreshTokenMethod: () => Promise<string>;
20
+ };
21
+ body?: any;
22
22
  }
23
- export declare function request(payload: RequestPayload): Promise<any>
23
+ export declare function request(payload: RequestPayload): Promise<any>;
@@ -1,69 +1,71 @@
1
- import { getEndpoint, NOTIFICATIONS } from "./endpoints.const"
2
- import { JWTUtils } from "./jwt.utils"
1
+ import { getEndpoint, NOTIFICATIONS } from "./endpoints.const";
2
+ import { JWTUtils } from "./jwt.utils";
3
3
  export class HttpError extends Error {
4
- status
5
- constructor(message, status) {
6
- super(message)
7
- this.status = status
8
- }
4
+ status;
5
+ constructor(message, status) {
6
+ super(message);
7
+ this.status = status;
8
+ }
9
9
  }
10
10
  export async function request(payload) {
11
- const headers = {}
12
- if (payload.camundaAuth) {
13
- if (JWTUtils.isExpired(payload.camundaAuth.token)) {
14
- const newToken = await payload.camundaAuth.refreshTokenMethod()
15
- headers.Authorization = `Bearer ${newToken}`
16
- } else {
17
- headers.Authorization = `Bearer ${payload.camundaAuth.token}`
18
- }
19
- }
20
- const type = payload.type ?? "json"
21
- if (type) {
22
- switch (type) {
23
- case "json":
24
- headers["Content-Type"] = "application/json"
25
- break
26
- case "text":
27
- headers["Content-Type"] = "text/plain"
28
- break
29
- }
30
- }
31
- const body = payload.body ? JSON.stringify(payload.body) : undefined
32
- let base
33
- if (payload.base) {
34
- switch (payload.base) {
35
- case "notifications":
36
- if (payload.endpoints?.notifications) {
37
- base = payload.endpoints.notifications
38
- } else if (payload.stage) {
39
- base = getEndpoint(payload.stage, NOTIFICATIONS)
40
- }
41
- break
42
- }
43
- }
44
- const url = base ? `${base}/${payload.url}` : payload.url
45
- const response = await fetch(url, {
46
- method: payload.method.toUpperCase(),
47
- headers,
48
- body,
49
- })
50
- let success = true
51
- if (response.status >= 400 && response.status < 500) {
52
- success = false
53
- }
54
- if (response.status >= 500) {
55
- success = false
56
- }
57
- if (!success) {
58
- throw new HttpError(response.statusText, response.status)
59
- }
60
- const responseType = payload.responseType ?? type
61
- switch (responseType) {
62
- case "json":
63
- return response.json()
64
- case "text":
65
- return response.text()
66
- default:
67
- return response
68
- }
11
+ const headers = {};
12
+ if (payload.camundaAuth) {
13
+ if (JWTUtils.isExpired(payload.camundaAuth.token)) {
14
+ const newToken = await payload.camundaAuth.refreshTokenMethod();
15
+ headers.Authorization = `Bearer ${newToken}`;
16
+ }
17
+ else {
18
+ headers.Authorization = `Bearer ${payload.camundaAuth.token}`;
19
+ }
20
+ }
21
+ const type = payload.type ?? "json";
22
+ if (type) {
23
+ switch (type) {
24
+ case "json":
25
+ headers["Content-Type"] = "application/json";
26
+ break;
27
+ case "text":
28
+ headers["Content-Type"] = "text/plain";
29
+ break;
30
+ }
31
+ }
32
+ const body = payload.body ? JSON.stringify(payload.body) : undefined;
33
+ let base;
34
+ if (payload.base) {
35
+ switch (payload.base) {
36
+ case "notifications":
37
+ if (payload.endpoints?.notifications) {
38
+ base = payload.endpoints.notifications;
39
+ }
40
+ else if (payload.stage) {
41
+ base = getEndpoint(payload.stage, NOTIFICATIONS);
42
+ }
43
+ break;
44
+ }
45
+ }
46
+ const url = base ? `${base}/${payload.url}` : payload.url;
47
+ const response = await fetch(url, {
48
+ method: payload.method.toUpperCase(),
49
+ headers,
50
+ body,
51
+ });
52
+ let success = true;
53
+ if (response.status >= 400 && response.status < 500) {
54
+ success = false;
55
+ }
56
+ if (response.status >= 500) {
57
+ success = false;
58
+ }
59
+ if (!success) {
60
+ throw new HttpError(response.statusText, response.status);
61
+ }
62
+ const responseType = payload.responseType ?? type;
63
+ switch (responseType) {
64
+ case "json":
65
+ return response.json();
66
+ case "text":
67
+ return response.text();
68
+ default:
69
+ return response;
70
+ }
69
71
  }
@@ -1,17 +1,17 @@
1
1
  export interface Endpoint {
2
- id: string
3
- dev: string
4
- int: string
5
- prod: string
2
+ id: string;
3
+ dev: string;
4
+ int: string;
5
+ prod: string;
6
6
  }
7
7
  export interface Endpoints {
8
- notifications?: string
8
+ notifications?: string;
9
9
  }
10
- export declare const NOTIFICATIONS: Endpoint
11
- export declare type Stage = "dev" | "int" | "prod"
12
- export declare function getEndpoint(stage: Stage, endpoint: Endpoint): string
10
+ export declare const NOTIFICATIONS: Endpoint;
11
+ export declare type Stage = "dev" | "int" | "prod";
12
+ export declare function getEndpoint(stage: Stage, endpoint: Endpoint): string;
13
13
  export declare function getEndpointByOptions(options: {
14
- stage?: Stage
15
- endpoints?: Endpoints
16
- endpoint: Endpoint
17
- }): string
14
+ stage?: Stage;
15
+ endpoints?: Endpoints;
16
+ endpoint: Endpoint;
17
+ }): string;
@@ -1,29 +1,30 @@
1
1
  export const NOTIFICATIONS = {
2
- id: "notifications",
3
- dev: "https://notifications.cloud.dev.ultrawombat.com",
4
- int: "https://notifications.cloud.ultrawombat.com",
5
- prod: "https://notifications.cloud.camunda.io",
6
- }
2
+ id: "notifications",
3
+ dev: "https://notifications.cloud.dev.ultrawombat.com",
4
+ int: "https://notifications.cloud.ultrawombat.com",
5
+ prod: "https://notifications.cloud.camunda.io",
6
+ };
7
7
  export function getEndpoint(stage, endpoint) {
8
- switch (stage) {
9
- case "dev":
10
- return endpoint.dev
11
- case "int":
12
- return endpoint.int
13
- case "prod":
14
- return endpoint.prod
15
- default:
16
- throw new Error(`Unknown stage: ${stage}`)
17
- }
8
+ switch (stage) {
9
+ case "dev":
10
+ return endpoint.dev;
11
+ case "int":
12
+ return endpoint.int;
13
+ case "prod":
14
+ return endpoint.prod;
15
+ default:
16
+ throw new Error(`Unknown stage: ${stage}`);
17
+ }
18
18
  }
19
19
  export function getEndpointByOptions(options) {
20
- switch (options.endpoint.id) {
21
- case "notifications":
22
- if (options.endpoints?.notifications) {
23
- return options.endpoints.notifications
24
- } else if (options.stage) {
25
- return getEndpoint(options.stage, options.endpoint)
26
- }
27
- }
28
- throw new Error(`Missing stage or notifications endpoint`)
20
+ switch (options.endpoint.id) {
21
+ case "notifications":
22
+ if (options.endpoints?.notifications) {
23
+ return options.endpoints.notifications;
24
+ }
25
+ else if (options.stage) {
26
+ return getEndpoint(options.stage, options.endpoint);
27
+ }
28
+ }
29
+ throw new Error(`Missing stage or notifications endpoint`);
29
30
  }
@@ -1,5 +1,5 @@
1
1
  export declare class JWTUtils {
2
- static decode(token: string): any
3
- static getExpiration(token: string): number
4
- static isExpired(token: string): boolean
2
+ static decode(token: string): any;
3
+ static getExpiration(token: string): number;
4
+ static isExpired(token: string): boolean;
5
5
  }
@@ -1,25 +1,23 @@
1
1
  export class JWTUtils {
2
- static decode(token) {
3
- const base64Url = token.split(".")[1]
4
- const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/")
5
- const jsonPayload = decodeURIComponent(
6
- window
7
- .atob(base64)
8
- .split("")
9
- .map(function (c) {
10
- return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2)
11
- })
12
- .join(""),
13
- )
14
- return JSON.parse(jsonPayload)
15
- }
16
- static getExpiration(token) {
17
- const decoded = JWTUtils.decode(token)
18
- return decoded.exp
19
- }
20
- static isExpired(token) {
21
- const expiration = JWTUtils.getExpiration(token)
22
- const now = new Date().getTime() / 1000
23
- return expiration < now
24
- }
2
+ static decode(token) {
3
+ const base64Url = token.split(".")[1];
4
+ const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
5
+ const jsonPayload = decodeURIComponent(window
6
+ .atob(base64)
7
+ .split("")
8
+ .map(function (c) {
9
+ return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
10
+ })
11
+ .join(""));
12
+ return JSON.parse(jsonPayload);
13
+ }
14
+ static getExpiration(token) {
15
+ const decoded = JWTUtils.decode(token);
16
+ return decoded.exp;
17
+ }
18
+ static isExpired(token) {
19
+ const expiration = JWTUtils.getExpiration(token);
20
+ const now = new Date().getTime() / 1000;
21
+ return expiration < now;
22
+ }
25
23
  }
@@ -1,68 +1,39 @@
1
- import { C3NotificationsProps } from "../components/c3-navigation/c3-navigation.types"
1
+ import { C3NotificationsProps } from "../components/c3-navigation/c3-navigation.types";
2
2
  export interface Notification {
3
- uuid: string
4
- userId?: string
5
- orgId?: string
6
- timestamp: number
7
- source: string
8
- type: string
9
- title: string
10
- description: string
11
- state: string
12
- meta?: {
13
- identifier?: string
14
- href?: string
15
- label?: string
16
- entity?: {
17
- id: string
18
- type: string
19
- }
20
- parentEntity?: {
21
- id: string
22
- type: string
23
- }
24
- }
3
+ uuid: string;
4
+ userId?: string;
5
+ orgId?: string;
6
+ timestamp: number;
7
+ source: string;
8
+ type: string;
9
+ title: string;
10
+ description: string;
11
+ state: string;
12
+ meta?: {
13
+ identifier?: string;
14
+ href?: string;
15
+ label?: string;
16
+ entity?: {
17
+ id: string;
18
+ type: string;
19
+ };
20
+ parentEntity?: {
21
+ id: string;
22
+ type: string;
23
+ };
24
+ };
25
25
  }
26
- export declare type AnalyticsEvent =
27
- | "notification-panel-opened"
28
- | "notification-clicked-cta"
26
+ export declare type AnalyticsEvent = "notification-panel-opened" | "notification-clicked-cta";
29
27
  export declare class NotificationService {
30
- static getNotifications(
31
- options: C3NotificationsProps,
32
- ): Promise<Notification[]>
33
- static sendAnalyticsEvent(
34
- options: C3NotificationsProps,
35
- eventOptions: {
36
- event: AnalyticsEvent
37
- id?: string
38
- },
39
- ): void
40
- static changeState(
41
- options: C3NotificationsProps,
42
- notificationId: string,
43
- operation: "read" | "dismiss",
44
- ): void
45
- static changeManyStates(
46
- options: C3NotificationsProps,
47
- notificationIds: string[],
48
- operation: "read" | "dismiss",
49
- ): void
50
- static notificationsStream(
51
- options: C3NotificationsProps,
52
- handler: (notification: Notification) => void,
53
- ): void
54
- static updateNotifications(
55
- allNotifications: Notification[],
56
- newNotification: Notification,
57
- ): Notification[]
58
- static updateNotificationState(
59
- allNotifications: Notification[],
60
- notificationId: string,
61
- newState: "read" | "dismiss",
62
- ): Notification[]
63
- static updateNotificationStates(
64
- allNotifications: Notification[],
65
- notificationIds: string[],
66
- newState: "read" | "dismiss",
67
- ): Notification[]
28
+ static getNotifications(options: C3NotificationsProps): Promise<Notification[]>;
29
+ static sendAnalyticsEvent(options: C3NotificationsProps, eventOptions: {
30
+ event: AnalyticsEvent;
31
+ id?: string;
32
+ }): void;
33
+ static changeState(options: C3NotificationsProps, notificationId: string, operation: "read" | "dismiss"): void;
34
+ static changeManyStates(options: C3NotificationsProps, notificationIds: string[], operation: "read" | "dismiss"): void;
35
+ static notificationsStream(options: C3NotificationsProps, handler: (notification: Notification) => void): void;
36
+ static updateNotifications(allNotifications: Notification[], newNotification: Notification): Notification[];
37
+ static updateNotificationState(allNotifications: Notification[], notificationId: string, newState: "read" | "dismiss"): Notification[];
38
+ static updateNotificationStates(allNotifications: Notification[], notificationIds: string[], newState: "read" | "dismiss"): Notification[];
68
39
  }