Skip to content

Commit 59d0cf4

Browse files
Add permision check for benchmark panel (#2108)
<!-- Ensure the title clearly reflects what was changed. Provide a clear and concise description of the changes made. The PR should only contain the changes related to the issue, and no other unrelated changes. --> Fixes OPS-3693
1 parent f55217c commit 59d0cf4

5 files changed

Lines changed: 89 additions & 51 deletions

File tree

packages/react-ui/src/app/features/home/components/home-onboarding-view.tsx

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { PermissionGuard } from '@/app/common/components/permission-guard';
21
import { useAuthorization } from '@/app/common/hooks/authorization-hooks';
32
import {
43
SETTINGS_KEYS,
@@ -64,7 +63,9 @@ const HomeOnboardingView = ({
6463
const { isCloudUser } = useShowTemplatesBanner();
6564

6665
const { checkAccess } = useAuthorization();
67-
const hasWriteFlowPermission = checkAccess(Permission.WRITE_FLOW);
66+
const hasBenchmarkPermissions =
67+
checkAccess(Permission.WRITE_FLOW) &&
68+
checkAccess(Permission.READ_APP_CONNECTION);
6869

6970
const { mutate: createFlow } = flowsHooks.useCreateFlow(navigate);
7071
const openBenchmarkWizard = useOpenBenchmarkWizard();
@@ -112,16 +113,13 @@ const HomeOnboardingView = ({
112113
return (
113114
<div className="flex flex-col gap-6 flex-1">
114115
{isFinOpsBenchmarkEnabled && (
115-
<PermissionGuard
116-
permission={[Permission.WRITE_FLOW, Permission.READ_APP_CONNECTION]}
117-
>
118-
<FinOpsBenchmarkBanner
119-
variation={benchmarkVariation}
120-
provider={benchmarkProvider}
121-
onActionClick={openBenchmarkWizard}
122-
onViewReportClick={onViewBenchmarkReportClick}
123-
/>
124-
</PermissionGuard>
116+
<FinOpsBenchmarkBanner
117+
variation={benchmarkVariation}
118+
provider={benchmarkProvider}
119+
onActionClick={openBenchmarkWizard}
120+
onViewReportClick={onViewBenchmarkReportClick}
121+
disabled={!hasBenchmarkPermissions}
122+
/>
125123
)}
126124
<ExploreTemplatesCarousel
127125
onSeeAllClick={onExploreTemplatesClick}
@@ -149,7 +147,7 @@ const HomeOnboardingView = ({
149147
<NoWorkflowsPlaceholder
150148
onExploreTemplatesClick={onExploreTemplatesClick}
151149
onNewWorkflowClick={
152-
hasWriteFlowPermission
150+
checkAccess(Permission.WRITE_FLOW)
153151
? () => {
154152
createFlow(undefined);
155153
}

packages/react-ui/src/app/features/home/components/home-operational-view.tsx

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { PermissionGuard } from '@/app/common/components/permission-guard';
1+
import { useAuthorization } from '@/app/common/hooks/authorization-hooks';
22
import { HomeFlowsTable } from '@/app/features/home/flows-table';
33
import {
44
useDashboardData,
@@ -49,6 +49,11 @@ const HomeOperationalView = ({
4949
variation: benchmarkVariation,
5050
provider: benchmarkProvider,
5151
} = useBenchmarkBannerState();
52+
const { checkAccess } = useAuthorization();
53+
const hasBenchmarkPermissions =
54+
checkAccess(Permission.WRITE_FLOW) &&
55+
checkAccess(Permission.READ_APP_CONNECTION);
56+
5257
const openBenchmarkWizard = useOpenBenchmarkWizard();
5358
const onViewBenchmarkReportClick = () =>
5459
navigate(`/analytics?dashboard=${benchmarkProvider}_benchmark`);
@@ -103,16 +108,13 @@ const HomeOperationalView = ({
103108
)}
104109

105110
{isFinOpsBenchmarkEnabled && (
106-
<PermissionGuard
107-
permission={[Permission.WRITE_FLOW, Permission.READ_APP_CONNECTION]}
108-
>
109-
<FinOpsBenchmarkBanner
110-
variation={benchmarkVariation}
111-
provider={benchmarkProvider}
112-
onActionClick={openBenchmarkWizard}
113-
onViewReportClick={onViewBenchmarkReportClick}
114-
/>
115-
</PermissionGuard>
111+
<FinOpsBenchmarkBanner
112+
variation={benchmarkVariation}
113+
provider={benchmarkProvider}
114+
onActionClick={openBenchmarkWizard}
115+
onViewReportClick={onViewBenchmarkReportClick}
116+
disabled={!hasBenchmarkPermissions}
117+
/>
116118
)}
117119

118120
<HomeFlowsTable

packages/react-ui/src/app/features/navigation/layout/secondary-left-side-panel-container.tsx

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { cn, ResizableHandle, ResizablePanel } from '@openops/components/ui';
2+
import { Permission } from '@openops/shared';
23
import { t } from 'i18next';
34
import { useCallback, useEffect, useMemo, useRef } from 'react';
45
import { ImperativePanelHandle } from 'react-resizable-panels';
56

7+
import { useAuthorization } from '@/app/common/hooks/authorization-hooks';
68
import { useResizablePanelGroup } from '@/app/common/hooks/use-resizable-panel-group';
79
import { RESIZABLE_PANEL_IDS } from '@/app/constants/layout';
810
import AssistantUiChat from '@/app/features/ai/assistant/assistant-ui-chat';
@@ -32,6 +34,11 @@ const SecondaryLeftSidePanelContainer = ({
3234
setIsSidebarMinimized: s.setIsSidebarMinimized,
3335
}));
3436

37+
const { checkAccess } = useAuthorization();
38+
const hasBenchmarkAccess =
39+
checkAccess(Permission.WRITE_FLOW) &&
40+
checkAccess(Permission.READ_APP_CONNECTION);
41+
3542
const { hasActiveAiSettings, isLoading } =
3643
aiSettingsHooks.useHasActiveAiSettings();
3744

@@ -43,22 +50,23 @@ const SecondaryLeftSidePanelContainer = ({
4350
}, [hasActiveAiSettings, isAiChatOpened, isLoading]);
4451

4552
const prevVisibilityRef = useRef({
46-
shouldShowBenchmark: isBenchmarkWizardOpen,
53+
shouldShowBenchmark: hasBenchmarkAccess && isBenchmarkWizardOpen,
4754
shouldShowAiChat,
4855
});
4956

50-
const shouldShowPanelContent = isBenchmarkWizardOpen || shouldShowAiChat;
57+
const shouldShowBenchmark = hasBenchmarkAccess && isBenchmarkWizardOpen;
58+
const shouldShowPanelContent = shouldShowBenchmark || shouldShowAiChat;
5159

5260
const getDefaultPanelSize = useCallback(() => {
5361
if (!shouldShowPanelContent) return 0;
5462
return getPanelSize(RESIZABLE_PANEL_IDS.SECONDARY_LEFT_SIDEBAR) ?? 20;
5563
}, [getPanelSize, shouldShowPanelContent]);
5664

5765
useEffect(() => {
58-
if (isBenchmarkWizardOpen) {
66+
if (shouldShowBenchmark) {
5967
setIsSidebarMinimized(true);
6068
}
61-
}, [isBenchmarkWizardOpen, setIsSidebarMinimized]);
69+
}, [shouldShowBenchmark, setIsSidebarMinimized]);
6270

6371
useEffect(() => {
6472
if (!resizablePanelRef.current) {
@@ -67,7 +75,7 @@ const SecondaryLeftSidePanelContainer = ({
6775

6876
const shouldUpdatePanel = shouldUpdatePanelVisibility(
6977
prevVisibilityRef.current,
70-
isBenchmarkWizardOpen,
78+
shouldShowBenchmark,
7179
shouldShowAiChat,
7280
);
7381

@@ -82,20 +90,20 @@ const SecondaryLeftSidePanelContainer = ({
8290
}
8391

8492
prevVisibilityRef.current = {
85-
shouldShowBenchmark: isBenchmarkWizardOpen,
93+
shouldShowBenchmark,
8694
shouldShowAiChat,
8795
};
8896
}, [
8997
shouldShowPanelContent,
9098
getPanelSize,
91-
isBenchmarkWizardOpen,
99+
shouldShowBenchmark,
92100
shouldShowAiChat,
93101
]);
94102

95103
const size = getSize(
96104
hasActiveAiSettings,
97105
isAiChatOpened,
98-
isBenchmarkWizardOpen,
106+
shouldShowBenchmark,
99107
);
100108

101109
return (
@@ -113,7 +121,7 @@ const SecondaryLeftSidePanelContainer = ({
113121
collapsedSize={0}
114122
defaultSize={getDefaultPanelSize()}
115123
>
116-
{isBenchmarkWizardOpen && (
124+
{shouldShowBenchmark && (
117125
<div className="w-full h-full dark:bg-background">
118126
<BenchmarkWizard onClose={() => setIsBenchmarkWizardOpen(false)} />
119127
</div>

packages/ui-components/src/components/finops-benchmark-banner/finops-benchmark-banner.tsx

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { t } from 'i18next';
33
import { LucideBarChart2, Sparkles } from 'lucide-react';
44
import { cn } from '../../lib/cn';
55
import { Button } from '../../ui/button';
6+
import { usePermissionMessage } from '../../ui/permission-message-context';
7+
import { TooltipWrapper } from '../tooltip-wrapper';
68

79
const finOpsBenchmarkBannerClasses =
810
'flex w-full items-center justify-between gap-4 rounded-[8px] border border-input bg-background-800 p-4';
@@ -30,6 +32,7 @@ type FinOpsBenchmarkBannerProps = {
3032
onActionClick?: () => void;
3133
onViewReportClick?: () => void;
3234
className?: string;
35+
disabled?: boolean;
3336
};
3437

3538
const FinOpsBenchmarkBanner = ({
@@ -38,7 +41,10 @@ const FinOpsBenchmarkBanner = ({
3841
onActionClick,
3942
onViewReportClick,
4043
className,
44+
disabled = false,
4145
}: FinOpsBenchmarkBannerProps) => {
46+
const permissionMessage = usePermissionMessage();
47+
const disabledTooltip = disabled ? permissionMessage : undefined;
4248
const providerLabel = PROVIDER_LABELS[provider];
4349

4450
const content =
@@ -70,25 +76,35 @@ const FinOpsBenchmarkBanner = ({
7076
</div>
7177
<div className={finOpsActionsVariants({ variation })}>
7278
{variation === 'report' && (
73-
<Button
74-
type="button"
75-
variant="ghost"
76-
className="h-auto gap-1 px-0 py-0 text-sm font-bold leading-5 text-primary-200 hover:bg-transparent hover:underline"
77-
onClick={onViewReportClick}
78-
>
79-
<LucideBarChart2 className="size-[18px]" />
80-
{content.reportLabel}
81-
</Button>
79+
<TooltipWrapper tooltipText={disabledTooltip}>
80+
<span className={cn({ 'cursor-not-allowed': disabled })}>
81+
<Button
82+
type="button"
83+
variant="ghost"
84+
disabled={disabled}
85+
className="h-auto gap-1 px-0 py-0 text-sm font-bold leading-5 text-primary-200 hover:bg-transparent hover:underline disabled:pointer-events-none disabled:opacity-50"
86+
onClick={onViewReportClick}
87+
>
88+
<LucideBarChart2 className="size-[18px]" />
89+
{content.reportLabel}
90+
</Button>
91+
</span>
92+
</TooltipWrapper>
8293
)}
83-
<Button
84-
type="button"
85-
variant="outline"
86-
className="h-[38px] gap-2 rounded-[8px] border-input bg-background px-3 py-[9px] text-sm font-bold leading-5 text-primary-200 hover:bg-accent/50"
87-
onClick={onActionClick}
88-
>
89-
<Sparkles className="size-5" />
90-
{content.actionLabel}
91-
</Button>
94+
<TooltipWrapper tooltipText={disabledTooltip}>
95+
<span className={cn({ 'cursor-not-allowed': disabled })}>
96+
<Button
97+
type="button"
98+
variant="outline"
99+
disabled={disabled}
100+
className="h-[38px] gap-2 rounded-[8px] border-input bg-background px-3 py-[9px] text-sm font-bold leading-5 text-primary-200 hover:bg-accent/50 disabled:pointer-events-none"
101+
onClick={onActionClick}
102+
>
103+
<Sparkles className="size-5" />
104+
{content.actionLabel}
105+
</Button>
106+
</span>
107+
</TooltipWrapper>
92108
</div>
93109
</div>
94110
);

packages/ui-components/src/stories/finops-benchmark-banner/finops-benchmark-banner.stories.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,17 @@ export const AzureReport: Story = {
4141
provider: 'azure',
4242
},
4343
};
44+
45+
export const DisabledDefault: Story = {
46+
args: {
47+
disabled: true,
48+
},
49+
};
50+
51+
export const DisabledReport: Story = {
52+
args: {
53+
variation: 'report',
54+
provider: 'aws',
55+
disabled: true,
56+
},
57+
};

0 commit comments

Comments
 (0)