Skip to content

Commit 2ede02a

Browse files
feixuanlimergify[bot]
authored andcommitted
feat(shared-link-settings-modal): Disable direct downloads if classified (#1500)
1 parent adae46d commit 2ede02a

File tree

10 files changed

+166
-16
lines changed

10 files changed

+166
-16
lines changed

i18n/en-US.properties

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1116,6 +1116,10 @@ boxui.share.sharedLinkSettings.allowDownloadLabel = Allow users with the Shared
11161116
boxui.share.sharedLinkSettings.allowDownloadTitle = Allow Download
11171117
# Label for Custom URL text input field
11181118
boxui.share.sharedLinkSettings.customURLLabel = Non-private custom URL
1119+
# Text to show that direct link download is disabled due to applied shield access policy with classification
1120+
boxui.share.sharedLinkSettings.directDownloadBlockedByAccessPolicyWithClassification = Download has been disabled for content due to the classification
1121+
# Text to show that direct link download is disabled due to applied shield access policy without classification
1122+
boxui.share.sharedLinkSettings.directDownloadBlockedByAccessPolicyWithoutClassification = Download has been disabled for content without classification.
11191123
# Title for Direct Link section
11201124
boxui.share.sharedLinkSettings.directLinkLabel = Direct Link
11211125
# Label for option to enable expiration on a Shared Link

src/features/shared-link-settings-modal/AllowDownloadSection.js

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,24 @@
11
import React from 'react';
22
import PropTypes from 'prop-types';
33
import { FormattedMessage } from 'react-intl';
4+
import classNames from 'classnames';
45

56
import Checkbox from '../../components/checkbox';
67
import TextInputWithCopyButton from '../../components/text-input-with-copy-button';
78
import Fieldset from '../../components/fieldset';
9+
import Tooltip from '../../components/tooltip';
810

911
import messages from './messages';
1012

1113
const AllowDownloadSection = ({
1214
canChangeDownload,
15+
classification,
1316
directLink,
1417
directLinkInputProps = {},
1518
downloadCheckboxProps = {},
1619
isDirectLinkAvailable,
1720
isDirectLinkUnavailableDueToDownloadSettings,
21+
isDirectLinkUnavailableDueToAccessPolicy,
1822
isDownloadAvailable,
1923
isDownloadEnabled,
2024
onChange,
@@ -35,23 +39,40 @@ const AllowDownloadSection = ({
3539
</div>
3640
);
3741

42+
const tooltipMessage = classification
43+
? { ...messages.directDownloadBlockedByAccessPolicyWithClassification }
44+
: { ...messages.directDownloadBlockedByAccessPolicyWithoutClassification };
45+
46+
const allowDownloadSectionClass = classNames('bdl-AllowDownloadSection', {
47+
'bdl-is-disabled': isDirectLinkUnavailableDueToAccessPolicy,
48+
});
49+
const isDirectLinkSectionVisible =
50+
(isDirectLinkAvailable || isDirectLinkUnavailableDueToDownloadSettings) && isDownloadEnabled;
51+
3852
if (isDownloadAvailable) {
3953
return (
40-
<div>
54+
<div className={allowDownloadSectionClass}>
4155
<hr />
42-
<Fieldset title={<FormattedMessage {...messages.allowDownloadTitle} />}>
43-
<Checkbox
44-
isChecked={isDownloadEnabled}
45-
isDisabled={!canChangeDownload}
46-
label={<FormattedMessage {...messages.allowDownloadLabel} />}
47-
name="isDownloadEnabled"
48-
onChange={onChange}
49-
{...downloadCheckboxProps}
50-
/>
51-
{(isDirectLinkAvailable || isDirectLinkUnavailableDueToDownloadSettings) && isDownloadEnabled
52-
? directLinkSection
53-
: null}
54-
</Fieldset>
56+
<Tooltip
57+
isDisabled={!isDirectLinkUnavailableDueToAccessPolicy}
58+
text={<FormattedMessage {...tooltipMessage} />}
59+
position="middle-left"
60+
>
61+
<Fieldset
62+
disabled={isDirectLinkUnavailableDueToAccessPolicy}
63+
title={<FormattedMessage {...messages.allowDownloadTitle} />}
64+
>
65+
<Checkbox
66+
isChecked={isDownloadEnabled}
67+
isDisabled={!canChangeDownload || isDirectLinkUnavailableDueToAccessPolicy}
68+
label={<FormattedMessage {...messages.allowDownloadLabel} />}
69+
name="isDownloadEnabled"
70+
onChange={onChange}
71+
{...downloadCheckboxProps}
72+
/>
73+
{isDirectLinkSectionVisible && directLinkSection}
74+
</Fieldset>
75+
</Tooltip>
5576
</div>
5677
);
5778
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.bdl-AllowDownloadSection {
2+
&.bdl-is-disabled {
3+
opacity: .5;
4+
}
5+
}

src/features/shared-link-settings-modal/README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,20 @@ const fakeRequest = val => {
2626
<SharedLinkSettingsModal
2727
accessLevel="peopleWithTheLink"
2828
canChangeVanityName
29+
item={{
30+
bannerPolicy: {
31+
body: 'test',
32+
},
33+
classification: 'internal',
34+
grantedPermissions: {
35+
itemShare: true
36+
},
37+
hideCollaborators: false,
38+
id: 12345,
39+
name: 'My Example Folder',
40+
type: 'folder',
41+
typedID: 'd_12345'
42+
}}
2943
isOpen
3044
onRequestClose={ () => setState({ isOpen: false })}
3145
onSubmit={ fakeRequest }
@@ -42,6 +56,7 @@ const fakeRequest = val => {
4256
directLink="https://box.com/download/path"
4357
isDirectLinkAvailable
4458
isDirectLinkUnavailableDueToDownloadSettings={ false }
59+
isDirectLinkUnavailableDueToAccessPolicy
4560
vanityNameInputProps={ { 'data-resin-target': 'test' } }
4661
passwordCheckboxProps={ { 'data-resin-target': 'test' } }
4762
passwordInputProps={ { 'data-resin-target': 'test' } }

src/features/shared-link-settings-modal/SharedLinkSettingsModal.js

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { Modal, ModalActions } from '../../components/modal';
88
import InlineNotice from '../../components/inline-notice';
99
import Link from '../../components/link/LinkBase';
1010
import commonMessages from '../../common/messages';
11+
import Classification from '../classification';
1112

1213
import VanityNameSection from './VanityNameSection';
1314
import PasswordSection from './PasswordSection';
@@ -108,6 +109,11 @@ class SharedLinkSettingsModal extends Component {
108109
isDirectLinkAvailable: PropTypes.bool.isRequired,
109110
/** Whether or not direct link is unavailable only due to download setting */
110111
isDirectLinkUnavailableDueToDownloadSettings: PropTypes.bool.isRequired,
112+
/** Whether or not direct link is unavailable only due to access policy setting */
113+
isDirectLinkUnavailableDueToAccessPolicy: PropTypes.bool.isRequired,
114+
115+
// Classification props
116+
item: PropTypes.object,
111117

112118
// Hooks for resin
113119
cancelButtonProps: PropTypes.object,
@@ -315,25 +321,48 @@ class SharedLinkSettingsModal extends Component {
315321
downloadCheckboxProps,
316322
isDirectLinkAvailable,
317323
isDirectLinkUnavailableDueToDownloadSettings,
324+
isDirectLinkUnavailableDueToAccessPolicy,
318325
isDownloadAvailable,
326+
item,
319327
} = this.props;
328+
320329
const { isDownloadEnabled } = this.state;
330+
const { classification } = item;
321331

322332
return (
323333
<AllowDownloadSection
324334
canChangeDownload={canChangeDownload}
335+
classification={classification}
325336
directLink={directLink}
326337
directLinkInputProps={directLinkInputProps}
327338
downloadCheckboxProps={downloadCheckboxProps}
328339
isDirectLinkAvailable={isDirectLinkAvailable}
329340
isDirectLinkUnavailableDueToDownloadSettings={isDirectLinkUnavailableDueToDownloadSettings}
341+
isDirectLinkUnavailableDueToAccessPolicy={isDirectLinkUnavailableDueToAccessPolicy}
330342
isDownloadAvailable={isDownloadAvailable}
331343
isDownloadEnabled={isDownloadEnabled}
332344
onChange={this.onAllowDownloadChange}
333345
/>
334346
);
335347
}
336348

349+
renderModalTitle() {
350+
const { item } = this.props;
351+
const { bannerPolicy, classification } = item;
352+
353+
return (
354+
<span className="bdl-SharedLinkSettingsModal-title">
355+
<FormattedMessage {...messages.modalTitle} />
356+
<Classification
357+
advisoryMessage={bannerPolicy ? bannerPolicy.body : undefined}
358+
messageStyle="tooltip"
359+
name={classification}
360+
className="bdl-SharedLinkSettingsModal-classification"
361+
/>
362+
</span>
363+
);
364+
}
365+
337366
render() {
338367
const {
339368
canChangeDownload,
@@ -356,13 +385,12 @@ class SharedLinkSettingsModal extends Component {
356385
);
357386

358387
const disableSaveBtn = !(canChangeDownload || canChangeExpiration || canChangePassword || canChangeVanityName);
359-
360388
return (
361389
<Modal
362390
className="shared-link-settings-modal"
363391
isOpen={isOpen}
364392
onRequestClose={submitting ? undefined : onRequestClose}
365-
title={<FormattedMessage {...messages.modalTitle} />}
393+
title={this.renderModalTitle()}
366394
{...modalProps}
367395
>
368396
<form onSubmit={this.onSubmit}>

src/features/shared-link-settings-modal/SharedLinkSettingsModal.scss

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,13 @@
4949
color: $bdl-gray-62;
5050
}
5151
}
52+
53+
/** title and classifiction label */
54+
.bdl-SharedLinkSettingsModal-title {
55+
display: flex;
56+
flex-flow: row wrap;
57+
}
58+
59+
.bdl-SharedLinkSettingsModal-classification {
60+
margin-left: 6px;
61+
}

src/features/shared-link-settings-modal/__tests__/AllowDownloadSection-test.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ describe('features/shared-link-settings-modal/AllowDownloadSection', () => {
1313
const directLink = 'box.com/download';
1414
const isDirectLinkAvailable = true;
1515
const isDirectLinkUnavailableDueToDownloadSettings = true;
16+
const isDirectLinkUnavailableDueToAccessPolicy = false;
1617

1718
const getWrapper = (props = {}) =>
1819
shallow(
@@ -21,6 +22,7 @@ describe('features/shared-link-settings-modal/AllowDownloadSection', () => {
2122
directLink={directLink}
2223
isDirectLinkAvailable={isDirectLinkAvailable}
2324
isDirectLinkUnavailableDueToDownloadSettings={isDirectLinkUnavailableDueToDownloadSettings}
25+
isDirectLinkUnavailableDueToAccessPolicy={isDirectLinkUnavailableDueToAccessPolicy}
2426
isDownloadAvailable={isDownloadAvailable}
2527
isDownloadEnabled={isDownloadEnabled}
2628
onChange={sandbox.stub()}
@@ -75,6 +77,16 @@ describe('features/shared-link-settings-modal/AllowDownloadSection', () => {
7577

7678
expect(wrapper.find('TextInputWithCopyButton').length).toBe(0);
7779
});
80+
81+
test('should render tooltip when direct download is disabled', () => {
82+
const wrapper = getWrapper({ isDirectLinkUnavailableDueToAccessPolicy: true });
83+
expect(wrapper.find('Tooltip').length).toBe(1);
84+
});
85+
86+
test('should render disabled state when direct download is disabled', () => {
87+
const wrapper = getWrapper({ isDirectLinkUnavailableDueToAccessPolicy: true });
88+
expect(wrapper.find('.bdl-is-disabled').length).toBe(1);
89+
});
7890
});
7991

8092
describe('isDownloadAvailable === false', () => {

src/features/shared-link-settings-modal/__tests__/SharedLinkSettingsModal-test.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,27 @@ describe('features/shared-link-settings-modal/SharedLinkSettingsModal', () => {
2323
const directLink = 'box.com/download';
2424
const isDirectLinkAvailable = true;
2525
const isDirectLinkUnavailableDueToDownloadSettings = true;
26+
const isDirectLinkUnavailableDueToAccessPolicy = true;
2627

2728
const getWrapper = (props = {}) =>
2829
shallow(
2930
<SharedLinkSettingsModal
3031
onSubmit={sandbox.stub()}
3132
canChangeVanityName={canChangeVanityName}
33+
item={{
34+
bannerPolicy: {
35+
body: 'test',
36+
},
37+
classification: 'internal',
38+
grantedPermissions: {
39+
itemShare: true,
40+
},
41+
hideCollaborators: false,
42+
id: 12345,
43+
name: 'My Example Folder',
44+
type: 'folder',
45+
typedID: 'd_12345',
46+
}}
3247
vanityName={vanityName}
3348
serverURL={serverURL}
3449
canChangePassword={canChangePassword}
@@ -41,6 +56,7 @@ describe('features/shared-link-settings-modal/SharedLinkSettingsModal', () => {
4156
directLink={directLink}
4257
isDirectLinkAvailable={isDirectLinkAvailable}
4358
isDirectLinkUnavailableDueToDownloadSettings={isDirectLinkUnavailableDueToDownloadSettings}
59+
isDirectLinkUnavailableDueToAccessPolicy={isDirectLinkUnavailableDueToAccessPolicy}
4460
{...props}
4561
/>,
4662
);
@@ -261,10 +277,19 @@ describe('features/shared-link-settings-modal/SharedLinkSettingsModal', () => {
261277
expect(section.prop('isDirectLinkUnavailableDueToDownloadSettings')).toEqual(
262278
isDirectLinkUnavailableDueToDownloadSettings,
263279
);
280+
expect(section.prop('isDirectLinkUnavailableDueToAccessPolicy')).toEqual(
281+
isDirectLinkUnavailableDueToAccessPolicy,
282+
);
264283
expect(section.prop('onChange')).toEqual(wrapper.instance().onAllowDownloadChange);
265284
});
266285
});
267286

287+
describe('renderModalTitle()', () => {
288+
const wrapper = getWrapper();
289+
const title = shallow(wrapper.instance().renderModalTitle());
290+
expect(title).toMatchSnapshot();
291+
});
292+
268293
describe('render()', () => {
269294
test('should render a Modal, form, close button, and save button', () => {
270295
const wrapper = getWrapper();
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[` 1`] = `
4+
<span
5+
className="bdl-SharedLinkSettingsModal-title"
6+
>
7+
<FormattedMessage
8+
defaultMessage="Shared Link Settings"
9+
id="boxui.share.sharedLinkSettings.modalTitle"
10+
/>
11+
<Classification
12+
advisoryMessage="test"
13+
className="bdl-SharedLinkSettingsModal-classification"
14+
messageStyle="tooltip"
15+
name="internal"
16+
/>
17+
</span>
18+
`;

src/features/shared-link-settings-modal/messages.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,18 @@ const messages = defineMessages({
1616
description: 'Title for Direct Link section',
1717
id: 'boxui.share.sharedLinkSettings.directLinkLabel',
1818
},
19+
directDownloadBlockedByAccessPolicyWithClassification: {
20+
defaultMessage: 'Download has been disabled for content due to the classification',
21+
description:
22+
'Text to show that direct link download is disabled due to applied shield access policy with classification',
23+
id: 'boxui.share.sharedLinkSettings.directDownloadBlockedByAccessPolicyWithClassification',
24+
},
25+
directDownloadBlockedByAccessPolicyWithoutClassification: {
26+
defaultMessage: 'Download has been disabled for content without classification.',
27+
description:
28+
'Text to show that direct link download is disabled due to applied shield access policy without classification',
29+
id: 'boxui.share.sharedLinkSettings.directDownloadBlockedByAccessPolicyWithoutClassification',
30+
},
1931
inaccessibleSettingsNotice: {
2032
defaultMessage: 'Certain settings may not be available for this item due to permissions.',
2133
description:

0 commit comments

Comments
 (0)