@camunda/camunda-composite-components 0.23.1 → 0.23.3
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/api/endpoints.const.js +2 -2
- package/lib/esm/src/components/c3-navigation/c3-navigation-appbar/c3-navigation-appbar.js +8 -4
- 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
|
@@ -6,11 +6,14 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
6
6
|
*/
|
|
7
7
|
import { HeaderGlobalAction, Tag } from '@carbon/react';
|
|
8
8
|
import { Analytics, Application, ArrowLeft, Building, CloudApp, Dashboard, DataBase, Debug, Diagram, Document, Folder, Help, IbmKnowledgeCatalog, Information, Network_3, Notification, Play, Search, Security, Settings, Task, Terminal, UserAvatar, UserMultiple, Workspace, } from '@carbon/react/icons/index.esm.js';
|
|
9
|
-
import { useState } from 'react';
|
|
9
|
+
import { useMemo, useState } from 'react';
|
|
10
|
+
import { C3NotificationContext, } from '../../c3-navigation/c3-notification-provider/c3-notification-provider.js';
|
|
10
11
|
import { C3NavigationV2 } from '../c3-navigation-v2.js';
|
|
11
12
|
import { C3InfoPanel } from '../tools/c3-info-panel.js';
|
|
13
|
+
import { C3NotificationsPanel } from '../tools/c3-notifications-panel.js';
|
|
12
14
|
import { C3UserPanel } from '../tools/c3-user-panel.js';
|
|
13
15
|
import { useC3NavigationV2 } from '../use-c3-navigation-v2.js';
|
|
16
|
+
import { buildClusterSidebarEntries } from '../use-cluster-sidebar-entries.js';
|
|
14
17
|
// ─── Shared layout wrapper ──────────────────────────────────────────────────
|
|
15
18
|
const MainContent = ({ sidebarExpanded = true, hasSidebar = true, children }) => (_jsx("main", { id: 'main-content', style: {
|
|
16
19
|
marginLeft: hasSidebar ? (sidebarExpanded ? '16rem' : '3rem') : '0',
|
|
@@ -485,6 +488,12 @@ export const ComplexTreeTemplate = () => {
|
|
|
485
488
|
};
|
|
486
489
|
// ─── Tool panels ────────────────────────────────────────────────────────────
|
|
487
490
|
const createStoryTools = () => [
|
|
491
|
+
{
|
|
492
|
+
key: 'notifications',
|
|
493
|
+
label: 'Notifications',
|
|
494
|
+
renderButton: ({ onClick, isActive }) => (_jsx(HeaderGlobalAction, { "aria-label": 'Notifications', onClick: onClick, isActive: isActive, children: _jsx(Notification, { size: 20 }) })),
|
|
495
|
+
panel: _jsx(C3NotificationsPanel, { onLinkClick: () => undefined }),
|
|
496
|
+
},
|
|
488
497
|
{
|
|
489
498
|
key: 'info',
|
|
490
499
|
label: 'Info',
|
|
@@ -561,8 +570,271 @@ export const ToolPanelsTemplate = () => {
|
|
|
561
570
|
},
|
|
562
571
|
],
|
|
563
572
|
});
|
|
564
|
-
return (_jsxs(
|
|
573
|
+
return (_jsxs(MockNotificationsProvider, { notifications: POPULATED_NOTIFICATIONS, children: [_jsx(C3NavigationV2, { ...navProps }), _jsxs(MainContent, { sidebarExpanded: isSidebarExpanded, children: [_jsx("h1", { children: "Tool Panels" }), _jsxs("p", { style: { marginTop: '1rem', color: 'var(--cds-text-secondary)' }, children: ["Click the header tool buttons to open their slide-over panels:", ' ', _jsx("strong", { children: "Notifications" }), " (seeded with a long list to show overflow + scrolling), ", _jsx("strong", { children: "Info" }), ", and", ' ', _jsx("strong", { children: "Account" }), ". ", _jsx("strong", { children: "Help" }), " is a plain button with no panel. Click outside or click the active tool button again to close."] }), _jsxs("p", { style: { marginTop: '0.5rem', color: 'var(--cds-text-secondary)' }, children: [_jsx("strong", { children: "Note:" }), " ", _jsx("code", { children: "C3NotificationsPanel" }), " reads from", ' ', _jsx("code", { children: "C3NotificationContext" }), " rather than props. This story stubs the context with static data; in SaaS consumers it is populated by", ' ', _jsx("code", { children: "C3NotificationProvider" }), " against the notifications API."] })] })] }));
|
|
574
|
+
};
|
|
575
|
+
// ─── Notifications mock (used by ToolPanelsTemplate) ────────────────────────
|
|
576
|
+
/**
|
|
577
|
+
* `C3NotificationsPanel` reads from `C3NotificationContext` rather than props.
|
|
578
|
+
* In SaaS that context is populated by `C3NotificationProvider` against the
|
|
579
|
+
* notifications API. For Storybook we stub it with static data.
|
|
580
|
+
*/
|
|
581
|
+
const MockNotificationsProvider = ({ notifications: initial, children }) => {
|
|
582
|
+
const [notifications, setNotifications] = useState(initial);
|
|
583
|
+
const value = useMemo(() => ({
|
|
584
|
+
enabled: true,
|
|
585
|
+
isFetching: false,
|
|
586
|
+
notifications,
|
|
587
|
+
markAsRead: () => undefined,
|
|
588
|
+
markAllAsRead: () => undefined,
|
|
589
|
+
dismiss: (n) => setNotifications((all) => all.filter((x) => x.uuid !== n.uuid)),
|
|
590
|
+
dismissAll: () => setNotifications([]),
|
|
591
|
+
analytics: () => undefined,
|
|
592
|
+
}), [notifications]);
|
|
593
|
+
return (_jsx(C3NotificationContext.Provider, { value: value, children: children }));
|
|
565
594
|
};
|
|
595
|
+
const MIN_MS = 60 * 1000;
|
|
596
|
+
const HOUR_MS = 60 * MIN_MS;
|
|
597
|
+
const DAY_MS = 24 * HOUR_MS;
|
|
598
|
+
/**
|
|
599
|
+
* ~24 notifications with varied state (new/read), length, and optional CTA
|
|
600
|
+
* metadata. Enough to overflow the panel and surface spacing / scroll issues.
|
|
601
|
+
*/
|
|
602
|
+
const POPULATED_NOTIFICATIONS = [
|
|
603
|
+
{
|
|
604
|
+
uuid: 'n1',
|
|
605
|
+
timestamp: Date.now() - 5 * MIN_MS,
|
|
606
|
+
source: 'modeler',
|
|
607
|
+
type: 'process-published',
|
|
608
|
+
title: 'Process application published',
|
|
609
|
+
description: 'Your "Customer Onboarding" process application was published to the production cluster.',
|
|
610
|
+
state: 'new',
|
|
611
|
+
meta: { identifier: 'proc-1', href: '#', label: 'Open in Modeler' },
|
|
612
|
+
},
|
|
613
|
+
{
|
|
614
|
+
uuid: 'n2',
|
|
615
|
+
timestamp: Date.now() - 30 * MIN_MS,
|
|
616
|
+
source: 'console',
|
|
617
|
+
type: 'cluster-ready',
|
|
618
|
+
title: 'Cluster ready',
|
|
619
|
+
description: 'The new "eu-west-1" cluster finished provisioning.',
|
|
620
|
+
state: 'new',
|
|
621
|
+
meta: { identifier: 'cluster-1', href: '#', label: 'Open cluster' },
|
|
622
|
+
},
|
|
623
|
+
{
|
|
624
|
+
uuid: 'n3',
|
|
625
|
+
timestamp: Date.now() - 1 * HOUR_MS,
|
|
626
|
+
source: 'optimize',
|
|
627
|
+
type: 'alert-triggered',
|
|
628
|
+
title: 'Alert triggered: SLA breach on Loan Approval',
|
|
629
|
+
description: 'An Optimize alert you own fired. 12 instances breached the configured 48h SLA in the last hour.',
|
|
630
|
+
state: 'new',
|
|
631
|
+
meta: { identifier: 'alert-12', href: '#', label: 'View alert' },
|
|
632
|
+
},
|
|
633
|
+
{
|
|
634
|
+
uuid: 'n4',
|
|
635
|
+
timestamp: Date.now() - 2 * HOUR_MS,
|
|
636
|
+
source: 'tasklist',
|
|
637
|
+
type: 'task-assigned',
|
|
638
|
+
title: 'Task assigned to you',
|
|
639
|
+
description: '3 new tasks in "Approvals" were assigned to you.',
|
|
640
|
+
state: 'new',
|
|
641
|
+
meta: { identifier: 'task-22', href: '#', label: 'Open Tasklist' },
|
|
642
|
+
},
|
|
643
|
+
{
|
|
644
|
+
uuid: 'n5',
|
|
645
|
+
timestamp: Date.now() - 3 * HOUR_MS,
|
|
646
|
+
source: 'modeler',
|
|
647
|
+
type: 'review-requested',
|
|
648
|
+
title: 'Review requested on "Invoice.bpmn"',
|
|
649
|
+
description: 'Julia Chen requested your review on a diagram.',
|
|
650
|
+
state: 'new',
|
|
651
|
+
meta: { identifier: 'file-9', href: '#', label: 'Open diagram' },
|
|
652
|
+
},
|
|
653
|
+
{
|
|
654
|
+
uuid: 'n6',
|
|
655
|
+
timestamp: Date.now() - 5 * HOUR_MS,
|
|
656
|
+
source: 'console',
|
|
657
|
+
type: 'cluster-upgraded',
|
|
658
|
+
title: 'Cluster upgraded',
|
|
659
|
+
description: '"prod-eu" was upgraded to 8.9.0-alpha5.',
|
|
660
|
+
state: 'read',
|
|
661
|
+
meta: { identifier: 'cluster-7', href: '#', label: 'Open cluster' },
|
|
662
|
+
},
|
|
663
|
+
{
|
|
664
|
+
uuid: 'n7',
|
|
665
|
+
timestamp: Date.now() - 8 * HOUR_MS,
|
|
666
|
+
source: 'operate',
|
|
667
|
+
type: 'incident',
|
|
668
|
+
title: 'Incident in "Order Fulfillment"',
|
|
669
|
+
description: 'An incident occurred in a running instance. Activity: "Reserve Stock".',
|
|
670
|
+
state: 'read',
|
|
671
|
+
meta: { identifier: 'inst-4711', href: '#', label: 'View incident' },
|
|
672
|
+
},
|
|
673
|
+
{
|
|
674
|
+
uuid: 'n8',
|
|
675
|
+
timestamp: Date.now() - 12 * HOUR_MS,
|
|
676
|
+
source: 'billing',
|
|
677
|
+
type: 'invoice-available',
|
|
678
|
+
title: 'Invoice available',
|
|
679
|
+
description: 'Your March invoice is ready to download.',
|
|
680
|
+
state: 'read',
|
|
681
|
+
meta: { identifier: 'inv-2026-03', href: '#', label: 'Download invoice' },
|
|
682
|
+
},
|
|
683
|
+
{
|
|
684
|
+
uuid: 'n9',
|
|
685
|
+
timestamp: Date.now() - 1 * DAY_MS,
|
|
686
|
+
source: 'optimize',
|
|
687
|
+
type: 'report-ready',
|
|
688
|
+
title: 'Weekly report ready',
|
|
689
|
+
description: 'Your scheduled Optimize report for last week is available.',
|
|
690
|
+
state: 'read',
|
|
691
|
+
meta: { identifier: 'report-42', href: '#', label: 'View report' },
|
|
692
|
+
},
|
|
693
|
+
{
|
|
694
|
+
uuid: 'n10',
|
|
695
|
+
timestamp: Date.now() - 1 * DAY_MS - 2 * HOUR_MS,
|
|
696
|
+
source: 'console',
|
|
697
|
+
type: 'cluster-paused',
|
|
698
|
+
title: 'Cluster paused',
|
|
699
|
+
description: '"dev-sandbox" was paused due to inactivity. Resume it from the console.',
|
|
700
|
+
state: 'read',
|
|
701
|
+
meta: { identifier: 'cluster-3', href: '#', label: 'Resume cluster' },
|
|
702
|
+
},
|
|
703
|
+
{
|
|
704
|
+
uuid: 'n11',
|
|
705
|
+
timestamp: Date.now() - 1 * DAY_MS - 6 * HOUR_MS,
|
|
706
|
+
source: 'modeler',
|
|
707
|
+
type: 'comment-added',
|
|
708
|
+
title: 'New comment on "Payroll.bpmn"',
|
|
709
|
+
description: 'Arvid Nielsen left a comment on task "Compute Net".',
|
|
710
|
+
state: 'read',
|
|
711
|
+
meta: { identifier: 'comment-88', href: '#', label: 'View comment' },
|
|
712
|
+
},
|
|
713
|
+
{
|
|
714
|
+
uuid: 'n12',
|
|
715
|
+
timestamp: Date.now() - 2 * DAY_MS,
|
|
716
|
+
source: 'admin',
|
|
717
|
+
type: 'role-changed',
|
|
718
|
+
title: 'Role changed',
|
|
719
|
+
description: 'Your role in "Acme Corp" changed from Developer to Admin.',
|
|
720
|
+
state: 'read',
|
|
721
|
+
},
|
|
722
|
+
{
|
|
723
|
+
uuid: 'n13',
|
|
724
|
+
timestamp: Date.now() - 2 * DAY_MS - 5 * HOUR_MS,
|
|
725
|
+
source: 'tasklist',
|
|
726
|
+
type: 'task-overdue',
|
|
727
|
+
title: 'Task overdue',
|
|
728
|
+
description: '"Review supplier contract" is overdue by 2 days.',
|
|
729
|
+
state: 'read',
|
|
730
|
+
meta: { identifier: 'task-9', href: '#', label: 'Open task' },
|
|
731
|
+
},
|
|
732
|
+
{
|
|
733
|
+
uuid: 'n14',
|
|
734
|
+
timestamp: Date.now() - 3 * DAY_MS,
|
|
735
|
+
source: 'billing',
|
|
736
|
+
type: 'plan-change',
|
|
737
|
+
title: 'Trial ending soon',
|
|
738
|
+
description: 'Your trial ends in 4 days. Upgrade now to keep access to all features, including multi-region clusters and Optimize alerts.',
|
|
739
|
+
state: 'read',
|
|
740
|
+
},
|
|
741
|
+
{
|
|
742
|
+
uuid: 'n15',
|
|
743
|
+
timestamp: Date.now() - 3 * DAY_MS - 4 * HOUR_MS,
|
|
744
|
+
source: 'modeler',
|
|
745
|
+
type: 'deployment-failed',
|
|
746
|
+
title: 'Deployment failed',
|
|
747
|
+
description: 'Deployment to "prod-eu" failed during validation. Open Modeler to inspect the errors.',
|
|
748
|
+
state: 'read',
|
|
749
|
+
meta: { identifier: 'deploy-55', href: '#', label: 'Inspect deployment' },
|
|
750
|
+
},
|
|
751
|
+
{
|
|
752
|
+
uuid: 'n16',
|
|
753
|
+
timestamp: Date.now() - 4 * DAY_MS,
|
|
754
|
+
source: 'operate',
|
|
755
|
+
type: 'instance-completed',
|
|
756
|
+
title: 'Long-running instance completed',
|
|
757
|
+
description: 'Instance 2001-001-9042 completed after 3 days.',
|
|
758
|
+
state: 'read',
|
|
759
|
+
meta: { identifier: 'inst-9042', href: '#', label: 'Open instance' },
|
|
760
|
+
},
|
|
761
|
+
{
|
|
762
|
+
uuid: 'n17',
|
|
763
|
+
timestamp: Date.now() - 5 * DAY_MS,
|
|
764
|
+
source: 'admin',
|
|
765
|
+
type: 'member-invited',
|
|
766
|
+
title: 'New member joined',
|
|
767
|
+
description: 'Priya Kapoor accepted the invitation to join "Acme Corp".',
|
|
768
|
+
state: 'read',
|
|
769
|
+
},
|
|
770
|
+
{
|
|
771
|
+
uuid: 'n18',
|
|
772
|
+
timestamp: Date.now() - 6 * DAY_MS,
|
|
773
|
+
source: 'console',
|
|
774
|
+
type: 'quota-warning',
|
|
775
|
+
title: 'Storage quota nearing limit',
|
|
776
|
+
description: 'You are using 87% of your included storage. Consider archiving old instances.',
|
|
777
|
+
state: 'read',
|
|
778
|
+
},
|
|
779
|
+
{
|
|
780
|
+
uuid: 'n19',
|
|
781
|
+
timestamp: Date.now() - 7 * DAY_MS,
|
|
782
|
+
source: 'optimize',
|
|
783
|
+
type: 'dashboard-shared',
|
|
784
|
+
title: 'Dashboard shared with you',
|
|
785
|
+
description: '"Q1 throughput" was shared with you by Miles Okonkwo.',
|
|
786
|
+
state: 'read',
|
|
787
|
+
meta: { identifier: 'dash-17', href: '#', label: 'Open dashboard' },
|
|
788
|
+
},
|
|
789
|
+
{
|
|
790
|
+
uuid: 'n20',
|
|
791
|
+
timestamp: Date.now() - 8 * DAY_MS,
|
|
792
|
+
source: 'tasklist',
|
|
793
|
+
type: 'form-published',
|
|
794
|
+
title: 'Form published',
|
|
795
|
+
description: '"Expense submission v3" is available to assignees.',
|
|
796
|
+
state: 'read',
|
|
797
|
+
meta: { identifier: 'form-31', href: '#', label: 'Open form' },
|
|
798
|
+
},
|
|
799
|
+
{
|
|
800
|
+
uuid: 'n21',
|
|
801
|
+
timestamp: Date.now() - 10 * DAY_MS,
|
|
802
|
+
source: 'modeler',
|
|
803
|
+
type: 'collaborator-added',
|
|
804
|
+
title: 'Added as collaborator',
|
|
805
|
+
description: 'Nadia Meyer added you as a collaborator on "Risk Engine".',
|
|
806
|
+
state: 'read',
|
|
807
|
+
},
|
|
808
|
+
{
|
|
809
|
+
uuid: 'n22',
|
|
810
|
+
timestamp: Date.now() - 12 * DAY_MS,
|
|
811
|
+
source: 'admin',
|
|
812
|
+
type: 'policy-updated',
|
|
813
|
+
title: 'Organization policy updated',
|
|
814
|
+
description: 'Password rotation policy was updated to require rotation every 90 days.',
|
|
815
|
+
state: 'read',
|
|
816
|
+
},
|
|
817
|
+
{
|
|
818
|
+
uuid: 'n23',
|
|
819
|
+
timestamp: Date.now() - 15 * DAY_MS,
|
|
820
|
+
source: 'billing',
|
|
821
|
+
type: 'payment-succeeded',
|
|
822
|
+
title: 'Payment received',
|
|
823
|
+
description: 'Your monthly payment for the Enterprise plan was received.',
|
|
824
|
+
state: 'read',
|
|
825
|
+
meta: { identifier: 'pay-0412', href: '#', label: 'View receipt' },
|
|
826
|
+
},
|
|
827
|
+
{
|
|
828
|
+
uuid: 'n24',
|
|
829
|
+
timestamp: Date.now() - 20 * DAY_MS,
|
|
830
|
+
source: 'console',
|
|
831
|
+
type: 'welcome',
|
|
832
|
+
title: 'Welcome to Camunda',
|
|
833
|
+
description: 'Thanks for signing up. Here are some resources to get you started.',
|
|
834
|
+
state: 'read',
|
|
835
|
+
meta: { identifier: 'welcome', href: '#', label: 'Open guide' },
|
|
836
|
+
},
|
|
837
|
+
];
|
|
566
838
|
// ─── Breadcrumb actions ─────────────────────────────────────────────────────
|
|
567
839
|
export const BreadcrumbActionsTemplate = () => {
|
|
568
840
|
const { navProps, isSidebarExpanded } = useC3NavigationV2({
|
|
@@ -736,6 +1008,250 @@ export const HeaderTrailingContentTemplate = () => {
|
|
|
736
1008
|
});
|
|
737
1009
|
return (_jsxs(_Fragment, { children: [_jsx(C3NavigationV2, { ...navProps }), _jsxs(MainContent, { sidebarExpanded: isSidebarExpanded, children: [_jsx("h1", { children: "Header Trailing Content" }), _jsxs("p", { style: { marginTop: '1rem', color: 'var(--cds-text-secondary)' }, children: ["The ", _jsx("code", { children: "headerTrailingContent" }), " prop renders content in the right-aligned header area, before the tool/action buttons. Used for license tags, environment badges, etc."] })] })] }));
|
|
738
1010
|
};
|
|
1011
|
+
// ─── Pruning (dead-node filter + group-item degradation) ────────────────────
|
|
1012
|
+
export const PruningTemplate = () => {
|
|
1013
|
+
const [activeKey, setActiveKey] = useState('label-1');
|
|
1014
|
+
const noop = () => undefined;
|
|
1015
|
+
const { navProps, isSidebarExpanded } = useC3NavigationV2({
|
|
1016
|
+
app: { ariaLabel: 'Pruning demo', linkProps: { href: '#' } },
|
|
1017
|
+
skipToContentTargetId: 'main-content',
|
|
1018
|
+
activeItemKey: activeKey,
|
|
1019
|
+
breadcrumbs: [{ key: 'root', label: 'Pruning demo', icon: Building }],
|
|
1020
|
+
sidebarChildren: [
|
|
1021
|
+
{
|
|
1022
|
+
type: 'item',
|
|
1023
|
+
key: 'label-1',
|
|
1024
|
+
label: 'label-1',
|
|
1025
|
+
icon: Dashboard,
|
|
1026
|
+
onClick: () => setActiveKey('label-1'),
|
|
1027
|
+
},
|
|
1028
|
+
{
|
|
1029
|
+
type: 'item',
|
|
1030
|
+
key: 'should-not-render-1',
|
|
1031
|
+
label: 'should-not-render-1',
|
|
1032
|
+
icon: Dashboard,
|
|
1033
|
+
},
|
|
1034
|
+
{
|
|
1035
|
+
type: 'item',
|
|
1036
|
+
key: 'label-2',
|
|
1037
|
+
label: 'label-2',
|
|
1038
|
+
icon: Dashboard,
|
|
1039
|
+
linkProps: { href: '#label-2' },
|
|
1040
|
+
},
|
|
1041
|
+
{
|
|
1042
|
+
type: 'group',
|
|
1043
|
+
key: 'should-not-render-2',
|
|
1044
|
+
label: 'should-not-render-2',
|
|
1045
|
+
icon: Folder,
|
|
1046
|
+
defaultExpanded: true,
|
|
1047
|
+
children: [],
|
|
1048
|
+
},
|
|
1049
|
+
{
|
|
1050
|
+
type: 'group',
|
|
1051
|
+
key: 'should-not-render-3',
|
|
1052
|
+
label: 'should-not-render-3',
|
|
1053
|
+
icon: Folder,
|
|
1054
|
+
defaultExpanded: true,
|
|
1055
|
+
children: [
|
|
1056
|
+
{
|
|
1057
|
+
type: 'item',
|
|
1058
|
+
key: 'should-not-render-4',
|
|
1059
|
+
label: 'should-not-render-4',
|
|
1060
|
+
icon: Dashboard,
|
|
1061
|
+
},
|
|
1062
|
+
],
|
|
1063
|
+
},
|
|
1064
|
+
{
|
|
1065
|
+
type: 'group',
|
|
1066
|
+
key: 'label-3',
|
|
1067
|
+
label: 'label-3',
|
|
1068
|
+
icon: Folder,
|
|
1069
|
+
defaultExpanded: true,
|
|
1070
|
+
children: [
|
|
1071
|
+
{
|
|
1072
|
+
type: 'item',
|
|
1073
|
+
key: 'label-4',
|
|
1074
|
+
label: 'label-4',
|
|
1075
|
+
icon: Dashboard,
|
|
1076
|
+
onClick: () => setActiveKey('label-4'),
|
|
1077
|
+
},
|
|
1078
|
+
],
|
|
1079
|
+
},
|
|
1080
|
+
{
|
|
1081
|
+
type: 'group-item',
|
|
1082
|
+
key: 'label-5',
|
|
1083
|
+
label: 'label-5',
|
|
1084
|
+
icon: Application,
|
|
1085
|
+
defaultExpanded: true,
|
|
1086
|
+
onClick: () => setActiveKey('label-5'),
|
|
1087
|
+
children: [
|
|
1088
|
+
{
|
|
1089
|
+
type: 'item',
|
|
1090
|
+
key: 'label-6',
|
|
1091
|
+
label: 'label-6',
|
|
1092
|
+
icon: Dashboard,
|
|
1093
|
+
onClick: () => setActiveKey('label-6'),
|
|
1094
|
+
},
|
|
1095
|
+
],
|
|
1096
|
+
},
|
|
1097
|
+
{
|
|
1098
|
+
type: 'group-item',
|
|
1099
|
+
key: 'label-7',
|
|
1100
|
+
label: 'label-7',
|
|
1101
|
+
icon: Application,
|
|
1102
|
+
onClick: () => setActiveKey('label-7'),
|
|
1103
|
+
children: [],
|
|
1104
|
+
},
|
|
1105
|
+
{
|
|
1106
|
+
type: 'group-item',
|
|
1107
|
+
key: 'should-not-render-5',
|
|
1108
|
+
label: 'should-not-render-5',
|
|
1109
|
+
icon: Application,
|
|
1110
|
+
children: [],
|
|
1111
|
+
},
|
|
1112
|
+
{
|
|
1113
|
+
type: 'section',
|
|
1114
|
+
key: 'interleaved-section',
|
|
1115
|
+
title: 'Interleaved',
|
|
1116
|
+
children: [
|
|
1117
|
+
{
|
|
1118
|
+
type: 'item',
|
|
1119
|
+
key: 'should-not-render-6',
|
|
1120
|
+
label: 'should-not-render-6',
|
|
1121
|
+
icon: Dashboard,
|
|
1122
|
+
},
|
|
1123
|
+
{
|
|
1124
|
+
type: 'item',
|
|
1125
|
+
key: 'label-8',
|
|
1126
|
+
label: 'label-8',
|
|
1127
|
+
icon: Dashboard,
|
|
1128
|
+
onClick: () => setActiveKey('label-8'),
|
|
1129
|
+
},
|
|
1130
|
+
{
|
|
1131
|
+
type: 'item',
|
|
1132
|
+
key: 'should-not-render-7',
|
|
1133
|
+
label: 'should-not-render-7',
|
|
1134
|
+
icon: Dashboard,
|
|
1135
|
+
},
|
|
1136
|
+
{
|
|
1137
|
+
type: 'item',
|
|
1138
|
+
key: 'label-9',
|
|
1139
|
+
label: 'label-9',
|
|
1140
|
+
icon: Dashboard,
|
|
1141
|
+
onClick: noop,
|
|
1142
|
+
},
|
|
1143
|
+
],
|
|
1144
|
+
},
|
|
1145
|
+
{
|
|
1146
|
+
type: 'section',
|
|
1147
|
+
key: 'should-not-render-section',
|
|
1148
|
+
title: 'should-not-render-section',
|
|
1149
|
+
children: [
|
|
1150
|
+
{
|
|
1151
|
+
type: 'item',
|
|
1152
|
+
key: 'should-not-render-8',
|
|
1153
|
+
label: 'should-not-render-8',
|
|
1154
|
+
icon: Dashboard,
|
|
1155
|
+
},
|
|
1156
|
+
],
|
|
1157
|
+
},
|
|
1158
|
+
],
|
|
1159
|
+
});
|
|
1160
|
+
return (_jsxs(_Fragment, { children: [_jsx(C3NavigationV2, { ...navProps }), _jsxs(MainContent, { sidebarExpanded: isSidebarExpanded, children: [_jsx("h1", { children: "Sidebar Pruning" }), _jsxs("p", { style: { marginTop: '1rem', color: 'var(--cds-text-secondary)' }, children: ["Only ", _jsx("code", { children: "label-*" }), " entries should render, in numeric order. Every ", _jsx("code", { children: "should-not-render-*" }), " node (dead items, empty groups, groups with only dead children, unclickable childless group-items, sections with no live children) is filtered out.", _jsx("code", { children: "label-7" }), " is a clickable group-item with no children and should render as a plain item (no chevron)."] })] })] }));
|
|
1161
|
+
};
|
|
1162
|
+
// ─── Build cluster sidebar entries (helper) ─────────────────────────────────
|
|
1163
|
+
const makeCluster = (overrides) => ({
|
|
1164
|
+
uuid: overrides.uuid,
|
|
1165
|
+
name: overrides.name,
|
|
1166
|
+
status: {
|
|
1167
|
+
console: 'Healthy',
|
|
1168
|
+
modeler: 'Healthy',
|
|
1169
|
+
tasklist: 'Healthy',
|
|
1170
|
+
operate: 'Healthy',
|
|
1171
|
+
optimize: 'Healthy',
|
|
1172
|
+
identity: 'Healthy',
|
|
1173
|
+
admin: 'Healthy',
|
|
1174
|
+
zeebe: overrides.zeebeStatus ?? 'Healthy',
|
|
1175
|
+
...overrides.appStatus,
|
|
1176
|
+
},
|
|
1177
|
+
endpoints: {
|
|
1178
|
+
console: `https://console.example.test/${overrides.uuid}`,
|
|
1179
|
+
modeler: `https://modeler.example.test/${overrides.uuid}`,
|
|
1180
|
+
tasklist: `https://tasklist.example.test/${overrides.uuid}`,
|
|
1181
|
+
operate: `https://operate.example.test/${overrides.uuid}`,
|
|
1182
|
+
optimize: `https://optimize.example.test/${overrides.uuid}`,
|
|
1183
|
+
identity: `https://admin.example.test/${overrides.uuid}`,
|
|
1184
|
+
admin: `https://admin.example.test/${overrides.uuid}`,
|
|
1185
|
+
},
|
|
1186
|
+
generation: {
|
|
1187
|
+
name: 'gen2',
|
|
1188
|
+
versions: {
|
|
1189
|
+
zeebe: overrides.zeebeVersion,
|
|
1190
|
+
operate: overrides.zeebeVersion,
|
|
1191
|
+
tasklist: overrides.zeebeVersion,
|
|
1192
|
+
optimize: overrides.zeebeVersion,
|
|
1193
|
+
connectors: overrides.zeebeVersion,
|
|
1194
|
+
},
|
|
1195
|
+
},
|
|
1196
|
+
});
|
|
1197
|
+
export const BuildClusterSidebarEntriesTemplate = () => {
|
|
1198
|
+
const clusters = useMemo(() => [
|
|
1199
|
+
makeCluster({
|
|
1200
|
+
uuid: 'modern',
|
|
1201
|
+
name: 'Modern Cluster',
|
|
1202
|
+
zeebeVersion: '8.9.0',
|
|
1203
|
+
}),
|
|
1204
|
+
makeCluster({
|
|
1205
|
+
uuid: 'legacy',
|
|
1206
|
+
name: 'Legacy Cluster',
|
|
1207
|
+
zeebeVersion: '8.8.0',
|
|
1208
|
+
}),
|
|
1209
|
+
makeCluster({
|
|
1210
|
+
uuid: 'paused',
|
|
1211
|
+
name: 'Paused Cluster',
|
|
1212
|
+
zeebeVersion: '8.9.0',
|
|
1213
|
+
zeebeStatus: 'Paused',
|
|
1214
|
+
appStatus: {
|
|
1215
|
+
operate: 'Paused',
|
|
1216
|
+
tasklist: 'Paused',
|
|
1217
|
+
optimize: 'Paused',
|
|
1218
|
+
},
|
|
1219
|
+
}),
|
|
1220
|
+
makeCluster({
|
|
1221
|
+
uuid: 'restricted',
|
|
1222
|
+
name: 'Restricted Cluster',
|
|
1223
|
+
zeebeVersion: '8.9.0',
|
|
1224
|
+
}),
|
|
1225
|
+
], []);
|
|
1226
|
+
const entries = useMemo(() => buildClusterSidebarEntries(clusters, {
|
|
1227
|
+
resolveClusterLinkProps: (cluster) => cluster.uuid === 'restricted'
|
|
1228
|
+
? undefined
|
|
1229
|
+
: { href: `#cluster/${cluster.uuid}` },
|
|
1230
|
+
isAppVisible: (app, cluster) => !(cluster.uuid === 'restricted' && app === 'optimize'),
|
|
1231
|
+
appTeaserRoutes: {
|
|
1232
|
+
operate: { href: '#teaser/operate' },
|
|
1233
|
+
tasklist: { href: '#teaser/tasklist' },
|
|
1234
|
+
optimize: { href: '#teaser/optimize' },
|
|
1235
|
+
admin: { href: '#teaser/admin' },
|
|
1236
|
+
},
|
|
1237
|
+
renderTrailingElement: (cluster) => cluster.uuid === 'paused' ? (_jsx(Tag, { type: 'gray', size: 'sm', style: { marginLeft: '0.375rem', flexShrink: 0 }, children: "Paused" })) : undefined,
|
|
1238
|
+
}), [clusters]);
|
|
1239
|
+
const { navProps, isSidebarExpanded } = useC3NavigationV2({
|
|
1240
|
+
app: { ariaLabel: 'Camunda Console', linkProps: { href: '#' } },
|
|
1241
|
+
skipToContentTargetId: 'main-content',
|
|
1242
|
+
activeItemKey: 'modern-operate',
|
|
1243
|
+
breadcrumbs: [{ key: 'org', label: 'Acme Corp', icon: Building }],
|
|
1244
|
+
sidebarChildren: [
|
|
1245
|
+
{
|
|
1246
|
+
type: 'section',
|
|
1247
|
+
key: 'clusters',
|
|
1248
|
+
title: 'Clusters',
|
|
1249
|
+
children: entries,
|
|
1250
|
+
},
|
|
1251
|
+
],
|
|
1252
|
+
});
|
|
1253
|
+
return (_jsxs(_Fragment, { children: [_jsx(C3NavigationV2, { ...navProps }), _jsxs(MainContent, { sidebarExpanded: isSidebarExpanded, children: [_jsx("h1", { children: "buildClusterSidebarEntries" }), _jsxs("p", { style: { marginTop: '1rem', color: 'var(--cds-text-secondary)' }, children: ["Helper for consumers that list clusters in their sidebar. Each cluster iterates the default apps (operate, tasklist, optimize, admin), resolves the ", _jsx("strong", { children: "admin/identity" }), " alias from zeebe version, and falls back to ", _jsx("code", { children: "appTeaserRoutes" }), " when unhealthy."] }), _jsxs("ul", { style: { marginTop: '1rem', color: 'var(--cds-text-secondary)' }, children: [_jsxs("li", { children: [_jsx("strong", { children: "Modern Cluster" }), " (zeebe 8.9.0): renders as a clickable group-item with the ", _jsx("em", { children: "Admin" }), " label."] }), _jsxs("li", { children: [_jsx("strong", { children: "Legacy Cluster" }), " (zeebe 8.8.0): renders the", _jsx("em", { children: " Identity" }), " label via internal version check."] }), _jsxs("li", { children: [_jsx("strong", { children: "Paused Cluster" }), ": apps route to teaser pages, trailing", _jsx("em", { children: " Paused" }), " tag, no cluster-level link resolved."] }), _jsxs("li", { children: [_jsx("strong", { children: "Restricted Cluster" }), ":", ' ', _jsx("code", { children: "resolveClusterLinkProps" }), "returns ", _jsx("code", { children: "undefined" }), " so it renders as a pure group (no cluster link), and ", _jsx("code", { children: "isAppVisible" }), " hides Optimize."] })] })] })] }));
|
|
1254
|
+
};
|
|
739
1255
|
// ─── Compact sections (back button pattern) ─────────────────────────────────
|
|
740
1256
|
export const CompactSectionTemplate = () => {
|
|
741
1257
|
const [activeKey, setActiveKey] = useState('email-notifications');
|
|
@@ -794,3 +1310,72 @@ export const CompactSectionTemplate = () => {
|
|
|
794
1310
|
});
|
|
795
1311
|
return (_jsxs(_Fragment, { children: [_jsx(C3NavigationV2, { ...navProps }), _jsxs(MainContent, { sidebarExpanded: isSidebarExpanded, children: [_jsx("h1", { children: "Compact Section (Back Button)" }), _jsxs("p", { style: { marginTop: '1rem', color: 'var(--cds-text-secondary)' }, children: ["The \"Back to home\" item sits in a ", _jsx("strong", { children: "compact section" }), ' ', "that renders flush against the sidebar chrome (no extra margin). The next section (\"Settings\") follows normally with its title and divider."] })] })] }));
|
|
796
1312
|
};
|
|
1313
|
+
// ─── Global action with custom element (C4Search-shaped) ────────────────────
|
|
1314
|
+
/**
|
|
1315
|
+
* Stand-in for a C4Search-style component: controlled `isExpanded`, swaps an
|
|
1316
|
+
* icon button for an inline input + popup when open. Used by the story below
|
|
1317
|
+
* to verify that custom elements supplied via `globalActions[].element`
|
|
1318
|
+
* render as direct children of the header bar (no wrapper) so their internal
|
|
1319
|
+
* popups get the right positioning context.
|
|
1320
|
+
*/
|
|
1321
|
+
const InlineSearch = ({ isExpanded, onChangeExpanded }) => {
|
|
1322
|
+
if (!isExpanded) {
|
|
1323
|
+
return (_jsx(HeaderGlobalAction, { "aria-label": 'Search', onClick: () => onChangeExpanded(true), children: _jsx(Search, { size: 20 }) }));
|
|
1324
|
+
}
|
|
1325
|
+
return (_jsxs("div", { style: {
|
|
1326
|
+
position: 'relative',
|
|
1327
|
+
display: 'flex',
|
|
1328
|
+
alignItems: 'center',
|
|
1329
|
+
height: '100%',
|
|
1330
|
+
}, children: [_jsx("input", {
|
|
1331
|
+
// biome-ignore lint/a11y/noAutofocus: search popup expects focus on open
|
|
1332
|
+
autoFocus: true, placeholder: 'Search\u2026', onBlur: () => onChangeExpanded(false), style: {
|
|
1333
|
+
width: '20rem',
|
|
1334
|
+
height: '2rem',
|
|
1335
|
+
padding: '0 var(--cds-spacing-04)',
|
|
1336
|
+
background: 'var(--cds-field)',
|
|
1337
|
+
border: '1px solid var(--cds-border-strong)',
|
|
1338
|
+
color: 'var(--cds-text-primary)',
|
|
1339
|
+
fontSize: '0.875rem',
|
|
1340
|
+
} }), _jsx("div", { role: 'listbox', "aria-label": 'Search results', style: {
|
|
1341
|
+
position: 'absolute',
|
|
1342
|
+
top: '100%',
|
|
1343
|
+
right: 0,
|
|
1344
|
+
marginTop: '0.25rem',
|
|
1345
|
+
minWidth: '20rem',
|
|
1346
|
+
padding: 'var(--cds-spacing-04)',
|
|
1347
|
+
background: 'var(--cds-layer-01)',
|
|
1348
|
+
border: '1px solid var(--cds-border-subtle)',
|
|
1349
|
+
boxShadow: 'var(--cds-shadow)',
|
|
1350
|
+
color: 'var(--cds-text-secondary)',
|
|
1351
|
+
fontSize: '0.875rem',
|
|
1352
|
+
zIndex: 9000,
|
|
1353
|
+
}, children: "Type to search\u2026" })] }));
|
|
1354
|
+
};
|
|
1355
|
+
export const GlobalActionWithCustomElementTemplate = () => {
|
|
1356
|
+
const [searchOpen, setSearchOpen] = useState(false);
|
|
1357
|
+
const { navProps, isSidebarExpanded } = useC3NavigationV2({
|
|
1358
|
+
app: { ariaLabel: 'Camunda Console', linkProps: { href: '#' } },
|
|
1359
|
+
skipToContentTargetId: 'main-content',
|
|
1360
|
+
activeItemKey: 'dashboard',
|
|
1361
|
+
breadcrumbs: [{ key: 'org', label: 'Acme Corp', icon: Building }],
|
|
1362
|
+
sidebarChildren: [
|
|
1363
|
+
{
|
|
1364
|
+
type: 'item',
|
|
1365
|
+
key: 'dashboard',
|
|
1366
|
+
label: 'Dashboard',
|
|
1367
|
+
icon: Dashboard,
|
|
1368
|
+
},
|
|
1369
|
+
],
|
|
1370
|
+
globalActions: [
|
|
1371
|
+
{
|
|
1372
|
+
key: 'search',
|
|
1373
|
+
label: 'Search',
|
|
1374
|
+
element: (_jsx(InlineSearch, { isExpanded: searchOpen, onChangeExpanded: setSearchOpen })),
|
|
1375
|
+
},
|
|
1376
|
+
{ key: 'notifications', label: 'Notifications', icon: Notification },
|
|
1377
|
+
{ key: 'help', label: 'Help', icon: Help },
|
|
1378
|
+
],
|
|
1379
|
+
});
|
|
1380
|
+
return (_jsxs(_Fragment, { children: [_jsx(C3NavigationV2, { ...navProps }), _jsxs(MainContent, { sidebarExpanded: isSidebarExpanded, children: [_jsx("h1", { children: "Global Action with Custom Element" }), _jsxs("p", { style: { marginTop: '1rem', color: 'var(--cds-text-secondary)' }, children: ["When a ", _jsx("code", { children: "globalActions" }), " entry supplies an", ' ', _jsx("code", { children: "element" }), ", the navigation renders it as a direct child of the header bar (no wrapper) so popups and inputs that rely on a stable positioning context (e.g. C4Search) work correctly. Click the search icon to expand the input and verify the popup positions against the search field, not against an unrelated parent."] })] })] }));
|
|
1381
|
+
};
|
|
@@ -4,12 +4,12 @@ import { PanelHeader, PanelTitle } from './panel-primitives.js';
|
|
|
4
4
|
const LinkList = styled.ul `
|
|
5
5
|
list-style: none;
|
|
6
6
|
margin: 0;
|
|
7
|
-
padding:
|
|
7
|
+
padding: var(--cds-spacing-03) 0;
|
|
8
8
|
`;
|
|
9
9
|
const LinkItem = styled.li ``;
|
|
10
10
|
const LinkButton = styled.button `
|
|
11
11
|
width: 100%;
|
|
12
|
-
padding: 0.625rem
|
|
12
|
+
padding: 0.625rem var(--cds-spacing-05);
|
|
13
13
|
background: transparent;
|
|
14
14
|
border: none;
|
|
15
15
|
cursor: pointer;
|