Skip to content

Commit

Permalink
feat(content-sidebar): Option to render Box AI nav button disabled (#…
Browse files Browse the repository at this point in the history
…3831)

* feat(content-sidebar): Option to render Box AI nav button disabled

* feat(content-sidebar): Option to render Box AI nav button disabled

* feat(content-sidebar): Option to render Box AI nav button disabled

* feat(content-sidebar): Option to render Box AI nav button disabled
  • Loading branch information
kkuliczkowski-box authored Jan 10, 2025
1 parent 5201382 commit 2ba1a10
Show file tree
Hide file tree
Showing 8 changed files with 174 additions and 33 deletions.
10 changes: 9 additions & 1 deletion src/elements/common/nav-button/NavButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type Props = {
component?: React.ComponentType<any>,
exact?: boolean,
isActive?: (match: Match, location: Location) => ?boolean,
isDisabled?: boolean,
onClick?: (event: SyntheticEvent<>) => void,
replace?: boolean,
strict?: boolean,
Expand All @@ -32,6 +33,7 @@ const NavButton = React.forwardRef<Props, React.Ref<any>>((props: Props, ref: Re
component: Component = PlainButton,
exact,
isActive,
isDisabled,
onClick,
replace,
strict,
Expand All @@ -40,14 +42,20 @@ const NavButton = React.forwardRef<Props, React.Ref<any>>((props: Props, ref: Re
} = props;
const path = typeof to === 'object' ? to.pathname : to;

const disabledClassName = 'bdl-is-disabled';

return (
<Route exact={exact} path={path} strict={strict}>
{({ history, location, match }) => {
const isActiveValue = !!(isActive ? isActive(match, location) : match);

return (
<Component
className={classNames(className, { [activeClassName]: isActiveValue })}
className={classNames(className, {
[activeClassName]: isActiveValue,
[disabledClassName]: isDisabled,
})}
isDisabled={isDisabled}
onClick={event => {
if (onClick) {
onClick(event);
Expand Down
18 changes: 18 additions & 0 deletions src/elements/common/nav-button/__tests__/NavButton.test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
import * as React from 'react';
import { mount, render } from 'enzyme';
import { MemoryRouter, Router } from 'react-router-dom';
import { render as rtlRender, screen } from '../../../../test-utils/testing-library';
import NavButton from '..';

describe('elements/common/nav-button/NavButton', () => {
const getNavButton = (content, { path = '/activity', ...props }) => (
<MemoryRouter initialEntries={[path]}>
<NavButton to={path} {...props}>
{content}
</NavButton>
</MemoryRouter>
);

describe('when active', () => {
test('applies its default activeClassName', () => {
const button = render(
Expand Down Expand Up @@ -54,6 +63,15 @@ describe('elements/common/nav-button/NavButton', () => {
});
});

describe('when disabled', () => {
test('applies bdl-is-disabled class name', () => {
const content = 'Activity';
rtlRender(getNavButton(content, { isDisabled: true }));

expect(screen.getByText(content, { selector: '.bdl-is-disabled' })).toBeInTheDocument();
});
});

describe('exact', () => {
test('does not do exact matching by default', () => {
const button = render(
Expand Down
9 changes: 8 additions & 1 deletion src/elements/content-sidebar/SidebarNav.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ const SidebarNav = ({
onPanelChange = noop,
}: Props) => {
const { enabled: hasBoxSign } = useFeatureConfig('boxSign');
const { disabledTooltip: boxAIDisabledTooltip, showOnlyNavButton: showOnlyBoxAINavButton } =
useFeatureConfig('boxai.sidebar');

const handleSidebarNavButtonClick = (sidebarview: string) => {
onPanelChange(sidebarview, false);
Expand All @@ -82,9 +84,14 @@ const SidebarNav = ({
data-resin-target={SIDEBAR_NAV_TARGETS.BOXAI}
data-target-id="SidebarNavButton-boxAI"
data-testid="sidebarboxai"
isDisabled={showOnlyBoxAINavButton}
onClick={handleSidebarNavButtonClick}
sidebarView={SIDEBAR_VIEW_BOXAI}
tooltip={intl.formatMessage(messages.sidebarBoxAITitle)}
tooltip={
showOnlyBoxAINavButton
? boxAIDisabledTooltip
: intl.formatMessage(messages.sidebarBoxAITitle)
}
>
<BoxAiLogo height={Size5} width={Size5} />
</SidebarNavButton>
Expand Down
3 changes: 3 additions & 0 deletions src/elements/content-sidebar/SidebarNavButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type Props = {
'data-testid'?: string,
children: React.Node,
elementId?: string,
isDisabled?: boolean,
isOpen?: boolean,
onClick?: (sidebarView: string) => void,
sidebarView: string,
Expand All @@ -28,6 +29,7 @@ const SidebarNavButton = React.forwardRef<Props, React.Ref<any>>((props: Props,
'data-testid': dataTestId,
children,
elementId = '',
isDisabled,
isOpen,
onClick = noop,
sidebarView,
Expand Down Expand Up @@ -61,6 +63,7 @@ const SidebarNavButton = React.forwardRef<Props, React.Ref<any>>((props: Props,
getDOMRef={ref}
id={id}
isActive={isActive}
isDisabled={isDisabled}
onClick={handleNavButtonClick}
replace={isExactMatch}
role="tab"
Expand Down
12 changes: 8 additions & 4 deletions src/elements/content-sidebar/SidebarPanels.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import SidebarUtils from './SidebarUtils';
import withSidebarAnnotations from './withSidebarAnnotations';
import { withAnnotatorContext } from '../common/annotator-context';
import { withAPIContext } from '../common/api-context';
import { withFeatureConsumer, isFeatureEnabled } from '../common/feature-checking';
import { getFeatureConfig, withFeatureConsumer, isFeatureEnabled } from '../common/feature-checking';
import { withRouterAndRef } from '../common/routing';
import {
ORIGIN_ACTIVITY_SIDEBAR,
Expand Down Expand Up @@ -237,8 +237,12 @@ class SidebarPanels extends React.Component<Props, State> {
const isMetadataSidebarRedesignEnabled = isFeatureEnabled(features, 'metadata.redesign.enabled');
const isMetadataAiSuggestionsEnabled = isFeatureEnabled(features, 'metadata.aiSuggestions.enabled');

const { showOnlyNavButton: showOnlyBoxAINavButton } = getFeatureConfig(features, 'boxai.sidebar');

const canShowBoxAISidebarPanel = hasBoxAI && !showOnlyBoxAINavButton;

const panelsEligibility = {
[SIDEBAR_VIEW_BOXAI]: hasBoxAI,
[SIDEBAR_VIEW_BOXAI]: canShowBoxAISidebarPanel,
[SIDEBAR_VIEW_DOCGEN]: hasDocGen,
[SIDEBAR_VIEW_SKILLS]: hasSkills,
[SIDEBAR_VIEW_ACTIVITY]: hasActivity,
Expand All @@ -254,7 +258,7 @@ class SidebarPanels extends React.Component<Props, State> {

return (
<Switch>
{hasBoxAI && (
{canShowBoxAISidebarPanel && (
<Route
exact
path={`/${SIDEBAR_VIEW_BOXAI}`}
Expand Down Expand Up @@ -437,7 +441,7 @@ class SidebarPanels extends React.Component<Props, State> {

if (showDefaultPanel) {
redirect = defaultPanel;
} else if (hasBoxAI) {
} else if (canShowBoxAISidebarPanel) {
redirect = SIDEBAR_VIEW_BOXAI;
} else if (hasDocGen) {
redirect = SIDEBAR_VIEW_DOCGEN;
Expand Down
51 changes: 51 additions & 0 deletions src/elements/content-sidebar/__tests__/SidebarNav.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as React from 'react';
import { MemoryRouter } from 'react-router-dom';
import userEvent from '@testing-library/user-event';
import { mount } from 'enzyme';
import { BoxAiLogo } from '@box/blueprint-web-assets/icons/Logo';
import AdditionalTabPlaceholder from '../additional-tabs/AdditionalTabPlaceholder';
Expand All @@ -14,6 +15,7 @@ import IconMetadataThick from '../../../icons/general/IconMetadataThick';
import SidebarNav from '../SidebarNav';
import SidebarNavButton from '../SidebarNavButton';
import SidebarNavSignButton from '../SidebarNavSignButton';
import { render, screen } from '../../../test-utils/testing-library';

describe('elements/content-sidebar/SidebarNav', () => {
const getWrapper = (props = {}, active = '', features = {}) =>
Expand All @@ -27,6 +29,14 @@ describe('elements/content-sidebar/SidebarNav', () => {
.find('SidebarNav')
.at(1);

const getSidebarNav = ({ path = '/', props, features }) => (
<MemoryRouter initialEntries={[path]}>
<FeatureProvider features={features}>
<SidebarNav {...props} />
</FeatureProvider>
</MemoryRouter>
);

test('should render skills tab', () => {
const props = {
hasSkills: true,
Expand Down Expand Up @@ -87,6 +97,47 @@ describe('elements/content-sidebar/SidebarNav', () => {
expect(wrapper.find(IconChatRound)).toHaveLength(0);
});

describe('should render box ai tab with correct disabled state and tooltip', () => {
test.each`
disabledTooltip | expectedTooltip
${'tooltip msg'} | ${'tooltip msg'}
${'another tooltip msg'} | ${'another tooltip msg'}
`(
'given feature boxai.sidebar.showOnlyNavButton = true and boxai.sidebar.disabledTooltip = $disabledTooltip, should render box ai tab with disabled state and tooltip = $expectedTooltip',
async ({ disabledTooltip, expectedTooltip }) => {
render(
getSidebarNav({
features: { boxai: { sidebar: { disabledTooltip, showOnlyNavButton: true } } },
props: { hasBoxAI: true },
}),
);

const button = screen.getByTestId('sidebarboxai');

await userEvent.hover(button);

expect(button).toHaveAttribute('aria-disabled', 'true');
expect(screen.getByText(expectedTooltip)).toBeInTheDocument();
},
);

test('given feature boxai.sidebar.showOnlyNavButton = false, should render box ai tab with default tooltip', async () => {
render(
getSidebarNav({
features: { boxai: { sidebar: { showOnlyNavButton: false } } },
props: { hasBoxAI: true },
}),
);

const button = screen.getByTestId('sidebarboxai');

await userEvent.hover(button);

expect(button).not.toHaveAttribute('aria-disabled');
expect(screen.getByText('Box AI')).toBeInTheDocument();
});
});

test('should have multiple tabs', () => {
const props = {
hasActivity: true,
Expand Down
Loading

0 comments on commit 2ba1a10

Please sign in to comment.