@camunda/camunda-composite-components 0.23.0 → 0.23.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/esm/package.json +1 -1
- package/lib/esm/src/components/c3-navigation/c3-navigation-appbar/c3-navigation-appbar.js +11 -7
- package/lib/esm/src/components/c3-navigation/c3-navigation-sidebar/c3-navigation-sidebar.js +8 -4
- package/lib/esm/src/components/c3-navigation/c3-notification-provider/c3-notification-container.d.ts +1 -1
- package/lib/esm/src/components/c3-navigation/c3-notification-provider/c3-notification-container.js +16 -11
- package/lib/esm/src/components/c3-navigation-v2/c3-breadcrumb-bar.js +10 -10
- package/lib/esm/src/components/c3-navigation-v2/c3-navigation-v2.js +10 -6
- package/lib/esm/src/components/c3-navigation-v2/c3-navigation-v2.types.d.ts +5 -1
- package/lib/esm/src/components/c3-navigation-v2/c3-sidebar.js +62 -25
- package/lib/esm/src/components/c3-navigation-v2/c3-tools-area.js +8 -2
- package/lib/esm/src/components/c3-navigation-v2/index.d.ts +2 -0
- package/lib/esm/src/components/c3-navigation-v2/index.js +1 -0
- package/lib/esm/src/components/c3-navigation-v2/stories/story-templates.d.ts +3 -0
- package/lib/esm/src/components/c3-navigation-v2/stories/story-templates.js +587 -2
- package/lib/esm/src/components/c3-navigation-v2/tools/c3-info-panel.js +2 -2
- package/lib/esm/src/components/c3-navigation-v2/tools/c3-notifications-panel.js +16 -11
- package/lib/esm/src/components/c3-navigation-v2/tools/c3-user-panel.js +12 -12
- package/lib/esm/src/components/c3-navigation-v2/tools/panel-primitives.js +1 -1
- package/lib/esm/src/components/c3-navigation-v2/use-camunda-tools.js +2 -2
- package/lib/esm/src/components/c3-navigation-v2/use-cluster-sidebar-entries.d.ts +58 -0
- package/lib/esm/src/components/c3-navigation-v2/use-cluster-sidebar-entries.js +84 -0
- package/lib/esm/src/components/c3-navigation-v2/use-cluster-webapp-breadcrumbs.js +7 -24
- package/lib/esm/src/index.d.ts +4 -2
- package/lib/esm/src/index.js +2 -1
- package/lib/esm/src/utils/camunda.d.ts +16 -0
- package/lib/esm/src/utils/camunda.js +29 -6
- package/package.json +2 -2
|
@@ -5,7 +5,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
5
5
|
* You may not use this file except in compliance with the commercial license.
|
|
6
6
|
*/
|
|
7
7
|
import { Button } from '@carbon/react';
|
|
8
|
-
import { useContext, useEffect } from 'react';
|
|
8
|
+
import { useContext, useEffect, useState } from 'react';
|
|
9
9
|
import styled from 'styled-components';
|
|
10
10
|
import { C3BellIcon } from '../../../assets/c3-icons.js';
|
|
11
11
|
import C3NotificationContainer, { NotificationDescription, NotificationTitle, } from '../../c3-navigation/c3-notification-provider/c3-notification-container.js';
|
|
@@ -18,26 +18,28 @@ const DismissAllButton = styled(Button) `
|
|
|
18
18
|
letter-spacing: var(--cds-helper-text-01-letter-spacing);
|
|
19
19
|
`;
|
|
20
20
|
const EmptyState = styled.div `
|
|
21
|
-
padding:
|
|
21
|
+
padding: var(--cds-spacing-05);
|
|
22
22
|
`;
|
|
23
23
|
const EmptyStateTitle = styled(NotificationTitle) `
|
|
24
|
-
margin-top:
|
|
24
|
+
margin-top: var(--cds-spacing-06);
|
|
25
25
|
`;
|
|
26
26
|
const EmptyStateDescription = styled(NotificationDescription) `
|
|
27
27
|
color: var(--cds-text-secondary);
|
|
28
|
-
margin-top:
|
|
28
|
+
margin-top: var(--cds-spacing-03);
|
|
29
29
|
`;
|
|
30
30
|
const sortDescending = (a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime();
|
|
31
31
|
export const C3NotificationsPanel = ({ onLinkClick, }) => {
|
|
32
|
-
const { notifications, markAllAsRead, dismiss, dismissAll } = useContext(C3NotificationContext);
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
|
|
32
|
+
const { enabled, notifications, markAllAsRead, dismiss, dismissAll, analytics, } = useContext(C3NotificationContext);
|
|
33
|
+
// Snapshot uuids that were unread when the panel opened so "new" dots
|
|
34
|
+
// persist until the panel closes, even after mark-as-read runs.
|
|
35
|
+
const [unreadAtOpen] = useState(() => new Set(notifications.filter((n) => n.state === 'new').map((n) => n.uuid)));
|
|
36
36
|
// biome-ignore lint/correctness/useExhaustiveDependencies: intentional mount-only
|
|
37
37
|
useEffect(() => {
|
|
38
38
|
const unread = notifications.filter((n) => n.state === 'new');
|
|
39
39
|
if (unread.length)
|
|
40
40
|
markAllAsRead(unread);
|
|
41
|
+
if (enabled)
|
|
42
|
+
analytics('notification-panel-opened');
|
|
41
43
|
}, []);
|
|
42
44
|
return (_jsxs(_Fragment, { children: [_jsxs(PanelHeader, { style: {
|
|
43
45
|
width: '100%',
|
|
@@ -46,7 +48,10 @@ export const C3NotificationsPanel = ({ onLinkClick, }) => {
|
|
|
46
48
|
flexDirection: 'row',
|
|
47
49
|
justifyContent: 'space-between',
|
|
48
50
|
alignItems: 'center',
|
|
49
|
-
}, children: [_jsx(PanelTitle, { children: "Notifications" }), notifications.length > 0 && (_jsx(DismissAllButton, { kind: 'ghost', size: 'sm', onClick: () => dismissAll(notifications), children: "Dismiss all" }))] }), notifications.length > 0 ? ([...notifications]
|
|
50
|
-
|
|
51
|
-
|
|
51
|
+
}, children: [_jsx(PanelTitle, { children: "Notifications" }), notifications.length > 0 && (_jsx(DismissAllButton, { kind: 'ghost', size: 'sm', onClick: () => dismissAll(notifications), children: "Dismiss all" }))] }), notifications.length > 0 ? ([...notifications].sort(sortDescending).map((notification) => (_jsx(C3NotificationContainer, { onRead: () => undefined, onDismiss: () => dismiss(notification), originalOnLinkClick: onLinkClick, onLinkClick: () => {
|
|
52
|
+
if (enabled) {
|
|
53
|
+
analytics('notification-clicked-cta', notification.meta?.identifier);
|
|
54
|
+
}
|
|
55
|
+
onLinkClick?.(notification.meta);
|
|
56
|
+
}, unread: unreadAtOpen.has(notification.uuid), ...notification }, notification.uuid)))) : (_jsxs(EmptyState, { children: [_jsx(C3BellIcon, { size: 56 }), _jsx(EmptyStateTitle, { children: "No notifications" }), _jsx(EmptyStateDescription, { children: "New updates regarding your processes, clusters and more will appear here." })] }))] }));
|
|
52
57
|
};
|
|
@@ -11,11 +11,11 @@ import { useC3Profile, } from '../../c3-user-configuration/c3-profile-provider/c
|
|
|
11
11
|
import { useC3UserConfiguration } from '../../c3-user-configuration/c3-user-configuration-provider.js';
|
|
12
12
|
import { PanelHeader, PanelTitle } from './panel-primitives.js';
|
|
13
13
|
const ProfileSection = styled.div `
|
|
14
|
-
padding:
|
|
14
|
+
padding: var(--cds-spacing-05);
|
|
15
15
|
display: flex;
|
|
16
16
|
flex-direction: column;
|
|
17
|
-
gap:
|
|
18
|
-
border-bottom: 1px solid var(--cds-border-subtle);
|
|
17
|
+
gap: var(--cds-spacing-01);
|
|
18
|
+
border-bottom: 1px solid var(--cds-border-subtle-01);
|
|
19
19
|
`;
|
|
20
20
|
const ProfileName = styled.span `
|
|
21
21
|
font-size: var(--cds-body-01-font-size);
|
|
@@ -27,21 +27,21 @@ const ProfileEmail = styled.span `
|
|
|
27
27
|
color: var(--cds-text-secondary);
|
|
28
28
|
`;
|
|
29
29
|
const ThemeSection = styled.div `
|
|
30
|
-
padding:
|
|
31
|
-
border-bottom: 1px solid var(--cds-border-subtle);
|
|
30
|
+
padding: var(--cds-spacing-05);
|
|
31
|
+
border-bottom: 1px solid var(--cds-border-subtle-01);
|
|
32
32
|
`;
|
|
33
33
|
const CustomSection = styled.div `
|
|
34
|
-
border-bottom: 1px solid var(--cds-border-subtle);
|
|
34
|
+
border-bottom: 1px solid var(--cds-border-subtle-01);
|
|
35
35
|
`;
|
|
36
36
|
const ElementList = styled.ul `
|
|
37
37
|
list-style: none;
|
|
38
38
|
margin: 0;
|
|
39
|
-
padding:
|
|
39
|
+
padding: var(--cds-spacing-03) 0;
|
|
40
40
|
`;
|
|
41
41
|
const ElementItem = styled.li ``;
|
|
42
42
|
const ElementButton = styled.button `
|
|
43
43
|
width: 100%;
|
|
44
|
-
padding: 0.625rem
|
|
44
|
+
padding: 0.625rem var(--cds-spacing-05);
|
|
45
45
|
background: transparent;
|
|
46
46
|
border: none;
|
|
47
47
|
cursor: pointer;
|
|
@@ -68,7 +68,7 @@ const BottomPinned = styled.div `
|
|
|
68
68
|
flex-direction: column;
|
|
69
69
|
`;
|
|
70
70
|
const BottomActions = styled.div `
|
|
71
|
-
border-top: 1px solid var(--cds-border-subtle);
|
|
71
|
+
border-top: 1px solid var(--cds-border-subtle-01);
|
|
72
72
|
display: flex;
|
|
73
73
|
flex-direction: column;
|
|
74
74
|
|
|
@@ -79,7 +79,7 @@ const BottomActions = styled.div `
|
|
|
79
79
|
}
|
|
80
80
|
`;
|
|
81
81
|
const VersionWrapper = styled.div `
|
|
82
|
-
padding:
|
|
82
|
+
padding: var(--cds-spacing-03) var(--cds-spacing-05);
|
|
83
83
|
`;
|
|
84
84
|
const VersionText = styled.p `
|
|
85
85
|
color: var(--cds-text-primary);
|
|
@@ -119,7 +119,7 @@ export const C3UserPanel = ({ name, email, version, onLogout, stageToggle, custo
|
|
|
119
119
|
const defaults = LEGAL_LINKS.filter((l) => !consumerKeys.has(l.key));
|
|
120
120
|
const allElements = [...(elements ?? []), ...defaults];
|
|
121
121
|
return (_jsxs(_Fragment, { children: [_jsx(PanelHeader, { children: _jsx(PanelTitle, { children: "Account" }) }), (name || email) && (_jsxs(ProfileSection, { children: [name && _jsx(ProfileName, { children: name }), email && _jsx(ProfileEmail, { children: email })] })), customSection && _jsx(CustomSection, { children: customSection }), handleTheme && (_jsx(ThemeSection, { children: _jsxs(Stack, { gap: 3, children: [_jsx(FormLabel, { children: "Theme" }), _jsxs(RadioButtonGroup, { name: 'theme', valueSelected: theme, onChange: (value) => onThemeChange(value), orientation: 'vertical', children: [_jsx(RadioButton, { value: 'light', labelText: 'Light', id: 'theme-light' }), _jsx(RadioButton, { value: 'dark', labelText: 'Dark', id: 'theme-dark' }), _jsx(RadioButton, { value: 'system', labelText: 'System', id: 'theme-system' })] })] }) })), stageToggle && (_jsx("div", { style: {
|
|
122
|
-
padding: '
|
|
123
|
-
borderBottom: '1px solid var(--cds-border-subtle)',
|
|
122
|
+
padding: 'var(--cds-spacing-05)',
|
|
123
|
+
borderBottom: '1px solid var(--cds-border-subtle-01)',
|
|
124
124
|
}, children: _jsx(Toggle, { id: 'stage-toggle', labelText: 'Production features', toggled: stageToggle.prodFeaturesEnabled, onToggle: stageToggle.toggle, size: 'sm' }) })), allElements.length > 0 && (_jsx(ElementList, { children: allElements.map((element) => (_jsx(ElementItem, { children: _jsx(ElementButton, { type: 'button', onClick: element.onClick, children: element.label }) }, element.key))) })), _jsxs(BottomPinned, { children: [version && (_jsxs(VersionWrapper, { children: [_jsx(VersionText, { children: version }), _jsxs(Copyright, { children: ["\u00A9 Camunda Services GmbH ", new Date().getFullYear()] })] })), onLogout && (_jsx(BottomActions, { children: _jsx(Button, { kind: 'ghost', size: 'lg', onClick: onLogout, renderIcon: ArrowRight, children: "Log out" }) }))] })] }));
|
|
125
125
|
};
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
const headerStyle = {
|
|
3
3
|
background: 'var(--cds-layer-01)',
|
|
4
4
|
boxShadow: 'inset 0 -1px 0 var(--cds-border-subtle-01)',
|
|
5
|
-
padding: '
|
|
5
|
+
padding: 'var(--cds-spacing-06) var(--cds-spacing-05) 13px',
|
|
6
6
|
flexShrink: 0,
|
|
7
7
|
};
|
|
8
8
|
const titleStyle = {
|
|
@@ -20,8 +20,8 @@ import { C3UserPanel } from './tools/c3-user-panel.js';
|
|
|
20
20
|
* Must be called within a C3UserConfigurationProvider tree (SaaS).
|
|
21
21
|
*/
|
|
22
22
|
export const useCamundaTools = (options) => {
|
|
23
|
-
const { notifications
|
|
24
|
-
const hasUnread =
|
|
23
|
+
const { notifications, isFetching } = useContext(C3NotificationContext);
|
|
24
|
+
const hasUnread = !isFetching && notifications.some((n) => n.state === 'new');
|
|
25
25
|
return useMemo(() => {
|
|
26
26
|
const tools = [];
|
|
27
27
|
if (options.notifications !== undefined) {
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import type { CamundaApp, Cluster } from '../../utils/camunda.types';
|
|
3
|
+
import type { LinkProps } from './c3-navigation-v2.types';
|
|
4
|
+
import type { GroupDescriptor, GroupItemDescriptor } from './use-c3-navigation-v2';
|
|
5
|
+
type ActiveMatcher = boolean | string | ((activeItemKey: string) => boolean);
|
|
6
|
+
export interface UseClusterSidebarEntriesOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Hide apps the current user can't see. Receives the canonical app key
|
|
9
|
+
* from the iteration list (e.g. `'admin'`), never the resolved `identity`
|
|
10
|
+
* alias, so consumers don't have to branch on version.
|
|
11
|
+
*/
|
|
12
|
+
isAppVisible?: (app: CamundaApp, cluster: Cluster) => boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Resolves the parent cluster's click target. When it returns link props,
|
|
15
|
+
* the entry renders as a `group-item` (clickable + expandable). When
|
|
16
|
+
* omitted or returning `undefined`, it renders as a pure `group`.
|
|
17
|
+
*/
|
|
18
|
+
resolveClusterLinkProps?: (cluster: Cluster) => LinkProps | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Active-state matcher for the cluster row. Mirrors the sidebar descriptor
|
|
21
|
+
* `isActive` shape (boolean, string, or `(activeItemKey) => boolean`).
|
|
22
|
+
* Ignored when the cluster renders as a pure group (no clickable target).
|
|
23
|
+
*/
|
|
24
|
+
isClusterActive?: (cluster: Cluster) => ActiveMatcher | undefined;
|
|
25
|
+
/**
|
|
26
|
+
* Fallback link props for paused or unhealthy clusters, per app. Keyable by
|
|
27
|
+
* either the canonical iteration value (`'admin'`) or the resolved alias
|
|
28
|
+
* (`'identity'`); both are checked, alias first.
|
|
29
|
+
*/
|
|
30
|
+
appTeaserRoutes?: Partial<Record<CamundaApp, LinkProps>>;
|
|
31
|
+
/**
|
|
32
|
+
* Consumer-provided labels, keyed by the display alias
|
|
33
|
+
* (`'admin'` or `'identity'` after version resolution). Fallback:
|
|
34
|
+
* `getReadableAppName(resolvedApp)`.
|
|
35
|
+
*/
|
|
36
|
+
appLabels?: Partial<Record<CamundaApp, string>>;
|
|
37
|
+
/** Per-cluster trailing badge (stage tag, etc.). */
|
|
38
|
+
renderTrailingElement?: (cluster: Cluster) => ReactNode;
|
|
39
|
+
/** Override the app list. Default: operate, tasklist, optimize, admin. */
|
|
40
|
+
apps?: CamundaApp[];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Pure builder used by `useClusterSidebarEntries`. Kept as a separate
|
|
44
|
+
* function so stories and tests can drive it with synthetic data without
|
|
45
|
+
* mocking `useC3Profile`. Not exported from the package surface; consumers
|
|
46
|
+
* use the hook.
|
|
47
|
+
*/
|
|
48
|
+
declare function buildClusterSidebarEntries(clusters: Cluster[], { isAppVisible, resolveClusterLinkProps, isClusterActive, appTeaserRoutes, appLabels, renderTrailingElement, apps, }: UseClusterSidebarEntriesOptions): Array<GroupDescriptor | GroupItemDescriptor>;
|
|
49
|
+
export { buildClusterSidebarEntries };
|
|
50
|
+
/**
|
|
51
|
+
* Builds cluster sidebar entries for consumers that list clusters in their
|
|
52
|
+
* sidebar (web modeler, console). Reads clusters from `useC3Profile`, iterates
|
|
53
|
+
* each cluster's available webapps, respects the identity/admin alias per
|
|
54
|
+
* cluster version, filters invisible or missing entries, and returns the
|
|
55
|
+
* sibling nodes ready to drop into a `SidebarSection`. Returns `[]` when
|
|
56
|
+
* nothing is renderable.
|
|
57
|
+
*/
|
|
58
|
+
export declare function useClusterSidebarEntries(options?: UseClusterSidebarEntriesOptions): Array<GroupDescriptor | GroupItemDescriptor>;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
|
|
3
|
+
* under one or more contributor license agreements. Licensed under a commercial license.
|
|
4
|
+
* You may not use this file except in compliance with the commercial license.
|
|
5
|
+
*/
|
|
6
|
+
import { CloudApp } from '@carbon/react/icons/index.esm.js';
|
|
7
|
+
import { useMemo } from 'react';
|
|
8
|
+
import { APP_ICONS, getEndpointForApp, getReadableAppName, isAdminApp, resolveAdminAppName, } from '../../utils/camunda.js';
|
|
9
|
+
import { useC3Profile } from '../c3-user-configuration/c3-profile-provider/c3-profile-provider.js';
|
|
10
|
+
const DEFAULT_APPS = ['operate', 'tasklist', 'optimize', 'admin'];
|
|
11
|
+
/**
|
|
12
|
+
* Pure builder used by `useClusterSidebarEntries`. Kept as a separate
|
|
13
|
+
* function so stories and tests can drive it with synthetic data without
|
|
14
|
+
* mocking `useC3Profile`. Not exported from the package surface; consumers
|
|
15
|
+
* use the hook.
|
|
16
|
+
*/
|
|
17
|
+
function buildClusterSidebarEntries(clusters, { isAppVisible, resolveClusterLinkProps, isClusterActive, appTeaserRoutes, appLabels, renderTrailingElement, apps = DEFAULT_APPS, }) {
|
|
18
|
+
return clusters.flatMap((cluster) => {
|
|
19
|
+
const children = apps.flatMap((app) => {
|
|
20
|
+
if (isAppVisible && !isAppVisible(app, cluster))
|
|
21
|
+
return [];
|
|
22
|
+
const resolvedApp = isAdminApp(app) ? resolveAdminAppName(cluster) : app;
|
|
23
|
+
const endpoint = getEndpointForApp(app, cluster.endpoints);
|
|
24
|
+
if (!endpoint)
|
|
25
|
+
return [];
|
|
26
|
+
const teaser = appTeaserRoutes?.[resolvedApp] ?? appTeaserRoutes?.[app];
|
|
27
|
+
// Admin has no dedicated status on the cluster DTO and doesn't depend
|
|
28
|
+
// on zeebe being up (it manages the cluster itself). Always link to
|
|
29
|
+
// the endpoint when present; consumers can still override via
|
|
30
|
+
// `appTeaserRoutes.admin` / `.identity` if they want a teaser page.
|
|
31
|
+
const linkProps = isAdminApp(app)
|
|
32
|
+
? (teaser ?? { href: endpoint })
|
|
33
|
+
: cluster.status?.[resolvedApp] === 'Healthy'
|
|
34
|
+
? { href: endpoint }
|
|
35
|
+
: teaser;
|
|
36
|
+
if (!linkProps)
|
|
37
|
+
return [];
|
|
38
|
+
return [
|
|
39
|
+
{
|
|
40
|
+
type: 'item',
|
|
41
|
+
key: `${cluster.uuid}-${resolvedApp}`,
|
|
42
|
+
label: appLabels?.[resolvedApp] ?? getReadableAppName(resolvedApp),
|
|
43
|
+
icon: APP_ICONS[resolvedApp],
|
|
44
|
+
linkProps,
|
|
45
|
+
},
|
|
46
|
+
];
|
|
47
|
+
});
|
|
48
|
+
if (children.length === 0)
|
|
49
|
+
return [];
|
|
50
|
+
const clusterLinkProps = resolveClusterLinkProps?.(cluster);
|
|
51
|
+
const base = {
|
|
52
|
+
key: `cluster-${cluster.uuid}`,
|
|
53
|
+
label: cluster.name,
|
|
54
|
+
icon: CloudApp,
|
|
55
|
+
trailingElement: renderTrailingElement?.(cluster),
|
|
56
|
+
children,
|
|
57
|
+
};
|
|
58
|
+
if (!clusterLinkProps) {
|
|
59
|
+
const group = { type: 'group', ...base };
|
|
60
|
+
return [group];
|
|
61
|
+
}
|
|
62
|
+
const activeMatcher = isClusterActive?.(cluster);
|
|
63
|
+
const groupItem = {
|
|
64
|
+
type: 'group-item',
|
|
65
|
+
...base,
|
|
66
|
+
linkProps: clusterLinkProps,
|
|
67
|
+
...(activeMatcher !== undefined ? { isActive: activeMatcher } : {}),
|
|
68
|
+
};
|
|
69
|
+
return [groupItem];
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
export { buildClusterSidebarEntries };
|
|
73
|
+
/**
|
|
74
|
+
* Builds cluster sidebar entries for consumers that list clusters in their
|
|
75
|
+
* sidebar (web modeler, console). Reads clusters from `useC3Profile`, iterates
|
|
76
|
+
* each cluster's available webapps, respects the identity/admin alias per
|
|
77
|
+
* cluster version, filters invisible or missing entries, and returns the
|
|
78
|
+
* sibling nodes ready to drop into a `SidebarSection`. Returns `[]` when
|
|
79
|
+
* nothing is renderable.
|
|
80
|
+
*/
|
|
81
|
+
export function useClusterSidebarEntries(options = {}) {
|
|
82
|
+
const { clusters } = useC3Profile();
|
|
83
|
+
return useMemo(() => buildClusterSidebarEntries(clusters ?? [], options), [clusters, options]);
|
|
84
|
+
}
|
|
@@ -3,28 +3,11 @@
|
|
|
3
3
|
* under one or more contributor license agreements. Licensed under a commercial license.
|
|
4
4
|
* You may not use this file except in compliance with the commercial license.
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
6
|
+
import { Building, CloudApp } from '@carbon/react/icons/index.esm.js';
|
|
7
7
|
import { useMemo } from 'react';
|
|
8
|
+
import { APP_ICONS, getReadableAppName } from '../../utils/camunda.js';
|
|
8
9
|
import { useC3Profile } from '../c3-user-configuration/c3-profile-provider/c3-profile-provider.js';
|
|
9
10
|
import { useC3UserConfiguration } from '../c3-user-configuration/c3-user-configuration-provider.js';
|
|
10
|
-
const APP_ICONS = {
|
|
11
|
-
operate: Play,
|
|
12
|
-
tasklist: Task,
|
|
13
|
-
optimize: Analytics,
|
|
14
|
-
admin: Settings,
|
|
15
|
-
identity: Settings,
|
|
16
|
-
modeler: Diagram,
|
|
17
|
-
console: Application,
|
|
18
|
-
};
|
|
19
|
-
const APP_LABELS = {
|
|
20
|
-
operate: 'Operate',
|
|
21
|
-
tasklist: 'Tasklist',
|
|
22
|
-
optimize: 'Optimize',
|
|
23
|
-
admin: 'Admin',
|
|
24
|
-
identity: 'Admin',
|
|
25
|
-
modeler: 'Modeler',
|
|
26
|
-
console: 'Console',
|
|
27
|
-
};
|
|
28
11
|
/**
|
|
29
12
|
* Apps shown in the app-switcher dropdown. Order determines display order.
|
|
30
13
|
* `identity` is excluded: it was deprecated in favor of `admin` (8.9+).
|
|
@@ -89,21 +72,21 @@ export function useClusterWebappBreadcrumbs(options) {
|
|
|
89
72
|
});
|
|
90
73
|
}
|
|
91
74
|
// ── App crumb ──────────────────────────────────────────────────────────
|
|
92
|
-
const appLabel =
|
|
93
|
-
const appIcon = APP_ICONS[currentApp]
|
|
75
|
+
const appLabel = getReadableAppName(currentApp);
|
|
76
|
+
const appIcon = APP_ICONS[currentApp];
|
|
94
77
|
const siblingApps = SWITCHABLE_APPS.filter((app) => app !== currentApp && currentCluster?.endpoints?.[app]);
|
|
95
78
|
const dropdownItems = siblingApps.length > 0
|
|
96
79
|
? [
|
|
97
80
|
{
|
|
98
81
|
key: currentApp,
|
|
99
82
|
label: appLabel,
|
|
100
|
-
icon:
|
|
83
|
+
icon: appIcon,
|
|
101
84
|
isSelected: true,
|
|
102
85
|
},
|
|
103
86
|
...siblingApps.map((app) => ({
|
|
104
87
|
key: app,
|
|
105
|
-
label:
|
|
106
|
-
icon: APP_ICONS[app]
|
|
88
|
+
label: getReadableAppName(app),
|
|
89
|
+
icon: APP_ICONS[app],
|
|
107
90
|
isSelected: false,
|
|
108
91
|
linkProps: resolveLinkProps(currentCluster?.endpoints[app] ?? '', app),
|
|
109
92
|
})),
|
package/lib/esm/src/index.d.ts
CHANGED
|
@@ -15,8 +15,8 @@ export { C3LicenseTag, type C3LicenseTagProps, } from './components/c3-license-t
|
|
|
15
15
|
export { default as C3Navigation } from './components/c3-navigation';
|
|
16
16
|
export { C3NavigationAppProps, C3NavigationElementProps, C3NavigationNavBarElement, C3NavigationNavBarProps, C3NavigationNavBarSubElement, C3NavigationProps, } from './components/c3-navigation/c3-navigation.types';
|
|
17
17
|
export { C3NavigationSideBarBaseProps } from './components/c3-navigation/c3-navigation-sidebar/c3-navigation-sidebar.types';
|
|
18
|
-
export type { AppProps as C3NavV2AppProps, BreadcrumbDescriptor, BreadcrumbDropdownItem, BreadcrumbSegment, C3NavigationV2Props, C3NotificationsPanelProps, C3UserPanelProps, GlobalActionButton, GroupDescriptor, GroupItemDescriptor, HelpToolOptions, ItemDescriptor, LinkComponent, LinkProps, NotificationsToolOptions, SectionDescriptor, SidebarGroup, SidebarGroupItem, SidebarItem, SidebarNode, SidebarNodeDescriptor, SidebarProps, SidebarSection, ToolDescriptor, UseC3NavigationV2Options, UseC3NavigationV2Return, UseCamundaToolsOptions, UserToolOptions, } from './components/c3-navigation-v2';
|
|
19
|
-
export { C3BreadcrumbBar as preview_C3BreadcrumbBar, C3NavigationV2 as preview_C3NavigationV2, C3NotificationsPanel as preview_C3NotificationsPanel, C3Sidebar as preview_C3Sidebar, C3ToolsArea as preview_C3ToolsArea, C3UserPanel as preview_C3UserPanel, useC3NavigationV2 as preview_useC3NavigationV2, useCamundaTools as preview_useCamundaTools, useClusterWebappBreadcrumbs as preview_useClusterWebappBreadcrumbs, } from './components/c3-navigation-v2';
|
|
18
|
+
export type { AppProps as C3NavV2AppProps, BreadcrumbDescriptor, BreadcrumbDropdownItem, BreadcrumbSegment, C3NavigationV2Props, C3NotificationsPanelProps, C3UserPanelProps, GlobalActionButton, GroupDescriptor, GroupItemDescriptor, HelpToolOptions, ItemDescriptor, LinkComponent, LinkProps, NotificationsToolOptions, SectionDescriptor, SidebarGroup, SidebarGroupItem, SidebarItem, SidebarNode, SidebarNodeDescriptor, SidebarProps, SidebarSection, ToolDescriptor, UseC3NavigationV2Options, UseC3NavigationV2Return, UseCamundaToolsOptions, UseClusterSidebarEntriesOptions, UserToolOptions, } from './components/c3-navigation-v2';
|
|
19
|
+
export { C3BreadcrumbBar as preview_C3BreadcrumbBar, C3NavigationV2 as preview_C3NavigationV2, C3NotificationsPanel as preview_C3NotificationsPanel, C3Sidebar as preview_C3Sidebar, C3ToolsArea as preview_C3ToolsArea, C3UserPanel as preview_C3UserPanel, useC3NavigationV2 as preview_useC3NavigationV2, useCamundaTools as preview_useCamundaTools, useClusterSidebarEntries as preview_useClusterSidebarEntries, useClusterWebappBreadcrumbs as preview_useClusterWebappBreadcrumbs, } from './components/c3-navigation-v2';
|
|
20
20
|
export { C3BreadcrumbProps } from './components/c3-page/c3-breadcrumb/c3-breadcrumb.types';
|
|
21
21
|
export { C3Page } from './components/c3-page/c3-page';
|
|
22
22
|
export { C3PageProps } from './components/c3-page/c3-page.types';
|
|
@@ -26,3 +26,5 @@ export { useC3Profile } from './components/c3-user-configuration/c3-profile-prov
|
|
|
26
26
|
export { C3UserConfiguration, default as C3UserConfigurationProvider, } from './components/c3-user-configuration/c3-user-configuration-provider';
|
|
27
27
|
export { C3ClusterUpdateManager } from './contexts/c3-cluster-update-manager';
|
|
28
28
|
export { useApi } from './hooks/useApi';
|
|
29
|
+
export { APP_ICONS, APPS, getReadableAppName, isAdminApp, } from './utils/camunda';
|
|
30
|
+
export type { CamundaApp, CamundaAppWithZeebe } from './utils/camunda.types';
|
package/lib/esm/src/index.js
CHANGED
|
@@ -13,10 +13,11 @@ export { C3HelpCenter } from './components/c3-help-center/c3-help-center.js';
|
|
|
13
13
|
export { useC3HelpCenter } from './components/c3-help-center/c3-help-center-provider.js';
|
|
14
14
|
export { C3LicenseTag, } from './components/c3-license-tag/index.js';
|
|
15
15
|
export { default as C3Navigation } from './components/c3-navigation/index.js';
|
|
16
|
-
export { C3BreadcrumbBar as preview_C3BreadcrumbBar, C3NavigationV2 as preview_C3NavigationV2, C3NotificationsPanel as preview_C3NotificationsPanel, C3Sidebar as preview_C3Sidebar, C3ToolsArea as preview_C3ToolsArea, C3UserPanel as preview_C3UserPanel, useC3NavigationV2 as preview_useC3NavigationV2, useCamundaTools as preview_useCamundaTools, useClusterWebappBreadcrumbs as preview_useClusterWebappBreadcrumbs, } from './components/c3-navigation-v2/index.js';
|
|
16
|
+
export { C3BreadcrumbBar as preview_C3BreadcrumbBar, C3NavigationV2 as preview_C3NavigationV2, C3NotificationsPanel as preview_C3NotificationsPanel, C3Sidebar as preview_C3Sidebar, C3ToolsArea as preview_C3ToolsArea, C3UserPanel as preview_C3UserPanel, useC3NavigationV2 as preview_useC3NavigationV2, useCamundaTools as preview_useCamundaTools, useClusterSidebarEntries as preview_useClusterSidebarEntries, useClusterWebappBreadcrumbs as preview_useClusterWebappBreadcrumbs, } from './components/c3-navigation-v2/index.js';
|
|
17
17
|
export { C3Page } from './components/c3-page/c3-page.js';
|
|
18
18
|
export { C3ResponsiveStack } from './components/c3-responsive-stack/c3-responsive-stack.js';
|
|
19
19
|
export { useC3Profile } from './components/c3-user-configuration/c3-profile-provider/c3-profile-provider.js';
|
|
20
20
|
export { default as C3UserConfigurationProvider, } from './components/c3-user-configuration/c3-user-configuration-provider.js';
|
|
21
21
|
export { C3ClusterUpdateManager } from './contexts/c3-cluster-update-manager.js';
|
|
22
22
|
export { useApi } from './hooks/useApi.js';
|
|
23
|
+
export { APP_ICONS, APPS, getReadableAppName, isAdminApp, } from './utils/camunda.js';
|
|
@@ -5,7 +5,22 @@ import type { CamundaApp, Cluster, Organization } from './camunda.types';
|
|
|
5
5
|
* The CamundaApp type still accepts 'identity' for backward compatibility.
|
|
6
6
|
*/
|
|
7
7
|
export declare const APPS: CamundaApp[];
|
|
8
|
+
type AppIconComponent = React.ComponentType<{
|
|
9
|
+
size?: number;
|
|
10
|
+
style?: React.CSSProperties;
|
|
11
|
+
}>;
|
|
12
|
+
/**
|
|
13
|
+
* Per-app iconography used across nav surfaces (cluster-webapp breadcrumbs,
|
|
14
|
+
* cluster sidebar entries, app switchers). `identity` and `admin` map to the
|
|
15
|
+
* same icon so consumers don't have to unify the alias themselves.
|
|
16
|
+
*/
|
|
17
|
+
export declare const APP_ICONS: Record<CamundaApp, AppIconComponent>;
|
|
8
18
|
export declare const isAdminApp: (app: CamundaApp | undefined) => boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Picks the display alias (`admin` vs `identity`) for a cluster by zeebe version.
|
|
21
|
+
* Renamed in 8.9.0-alpha5. URL and permission still live on `identity`.
|
|
22
|
+
*/
|
|
23
|
+
export declare const resolveAdminAppName: (cluster: Cluster) => "admin" | "identity";
|
|
9
24
|
export declare const getReadableAppName: (appName: CamundaApp) => string;
|
|
10
25
|
/**
|
|
11
26
|
* Gets the endpoint URL for an app, handling identity/admin aliasing.
|
|
@@ -19,3 +34,4 @@ export declare const isTrialExpired: (org: Organization) => boolean;
|
|
|
19
34
|
export declare const getOrgSalesPlan: (org: Organization) => string | undefined;
|
|
20
35
|
export declare const canUpgradePlan: (org: Organization) => boolean;
|
|
21
36
|
export declare const canCreateCluster: (org: Organization) => boolean;
|
|
37
|
+
export {};
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
* under one or more contributor license agreements. Licensed under a commercial license.
|
|
4
4
|
* You may not use this file except in compliance with the commercial license.
|
|
5
5
|
*/
|
|
6
|
+
import { Analytics, Application, Diagram, Play, Settings, Task, } from '@carbon/react/icons/index.esm.js';
|
|
7
|
+
import { checkVersion, VersionCheckOperator } from './versionCheck.utils.js';
|
|
6
8
|
/**
|
|
7
9
|
* List of Camunda apps for navigation.
|
|
8
10
|
* Note: Only 'admin' is included (not 'identity') to avoid duplicate menu entries.
|
|
@@ -16,15 +18,36 @@ export const APPS = [
|
|
|
16
18
|
'optimize',
|
|
17
19
|
'admin',
|
|
18
20
|
];
|
|
21
|
+
/**
|
|
22
|
+
* Per-app iconography used across nav surfaces (cluster-webapp breadcrumbs,
|
|
23
|
+
* cluster sidebar entries, app switchers). `identity` and `admin` map to the
|
|
24
|
+
* same icon so consumers don't have to unify the alias themselves.
|
|
25
|
+
*/
|
|
26
|
+
export const APP_ICONS = {
|
|
27
|
+
operate: Play,
|
|
28
|
+
tasklist: Task,
|
|
29
|
+
optimize: Analytics,
|
|
30
|
+
admin: Settings,
|
|
31
|
+
identity: Settings,
|
|
32
|
+
modeler: Diagram,
|
|
33
|
+
console: Application,
|
|
34
|
+
};
|
|
19
35
|
export const isAdminApp = (app) => {
|
|
20
36
|
return app === 'identity' || app === 'admin';
|
|
21
37
|
};
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
38
|
+
/**
|
|
39
|
+
* Picks the display alias (`admin` vs `identity`) for a cluster by zeebe version.
|
|
40
|
+
* Renamed in 8.9.0-alpha5. URL and permission still live on `identity`.
|
|
41
|
+
*/
|
|
42
|
+
export const resolveAdminAppName = (cluster) => checkVersion({
|
|
43
|
+
possiblyVersionOrDockerPath: cluster.generation?.versions?.zeebe,
|
|
44
|
+
trueForSnapshot: true,
|
|
45
|
+
versionToCompareTo: '8.9.0-alpha5',
|
|
46
|
+
operator: VersionCheckOperator.GreaterThanOrEqual,
|
|
47
|
+
})
|
|
48
|
+
? 'admin'
|
|
49
|
+
: 'identity';
|
|
50
|
+
export const getReadableAppName = (appName) => appName.charAt(0).toUpperCase() + appName.slice(1);
|
|
28
51
|
/**
|
|
29
52
|
* Gets the endpoint URL for an app, handling identity/admin aliasing.
|
|
30
53
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camunda/camunda-composite-components",
|
|
3
|
-
"version": "0.23.
|
|
3
|
+
"version": "0.23.2",
|
|
4
4
|
"description": "Camunda Composite Components",
|
|
5
5
|
"bugs": {
|
|
6
6
|
"url": "https://github.com/camunda/camunda-cloud-management-apps/issues"
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"styled-components": "6.4.0",
|
|
61
61
|
"typescript-eslint": "8.58.1",
|
|
62
62
|
"wait-on": "9.0.5",
|
|
63
|
-
"@camunda/ccma-shared-types": "0.0.
|
|
63
|
+
"@camunda/ccma-shared-types": "0.0.5"
|
|
64
64
|
},
|
|
65
65
|
"peerDependencies": {
|
|
66
66
|
"@carbon/react": "1.x",
|