box-ui-elements 20.0.0-next.2 → 20.0.0
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/cypress.config.ts +23 -0
- package/dist/explorer.js +1 -1
- package/dist/openwith.js +1 -1
- package/dist/picker.js +1 -1
- package/dist/preview.js +1 -1
- package/dist/sharing.css +1 -1
- package/dist/sharing.js +1 -1
- package/dist/sidebar.js +1 -1
- package/dist/uploader.js +1 -1
- package/es/constants.js +1 -1
- package/es/constants.js.flow +1 -1
- package/es/constants.js.map +1 -1
- package/es/features/shared-link-settings-modal/ExpirationSection.js +4 -2
- package/es/features/shared-link-settings-modal/ExpirationSection.js.flow +4 -2
- package/es/features/shared-link-settings-modal/ExpirationSection.js.map +1 -1
- package/es/features/shared-link-settings-modal/SharedLinkSettingsModal.js +5 -0
- package/es/features/shared-link-settings-modal/SharedLinkSettingsModal.js.flow +10 -1
- package/es/features/shared-link-settings-modal/SharedLinkSettingsModal.js.map +1 -1
- package/es/features/unified-share-modal/UnifiedShareForm.js +9 -4
- package/es/features/unified-share-modal/UnifiedShareForm.js.flow +10 -1
- package/es/features/unified-share-modal/UnifiedShareForm.js.map +1 -1
- package/es/features/unified-share-modal/UnifiedShareModal.scss +4 -0
- package/es/features/unified-share-modal/flowTypes.js.flow +5 -1
- package/es/features/unified-share-modal/flowTypes.js.map +1 -1
- package/package.json +7 -7
- package/src/constants.js +1 -1
- package/src/elements/README.md +37 -2
- package/src/features/shared-link-settings-modal/ExpirationSection.js +4 -2
- package/src/features/shared-link-settings-modal/SharedLinkSettingsModal.js +10 -1
- package/src/features/shared-link-settings-modal/__tests__/ExpirationSection.test.js +22 -1
- package/src/features/shared-link-settings-modal/__tests__/SharedLinkSettingsModal.test.js +10 -0
- package/src/features/unified-share-modal/UnifiedShareForm.js +10 -1
- package/src/features/unified-share-modal/UnifiedShareModal.scss +4 -0
- package/src/features/unified-share-modal/__tests__/UnifiedShareForm.test.js +44 -9
- package/src/features/unified-share-modal/flowTypes.js +5 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/features/unified-share-modal/flowTypes.js"],"names":["React","constants","accessLevelValues","ANYONE_WITH_LINK","ANYONE_IN_COMPANY","PEOPLE_IN_ITEM","permissionLevelValues","CAN_EDIT","CAN_VIEW_DOWNLOAD","CAN_VIEW_ONLY","collaboratorGroupValues","COLLAB_GROUP_TYPE","COLLAB_USER_TYPE","COLLAB_PENDING_TYPE"],"mappings":"AACA,OAAO,KAAKA,KAAZ,MAAuB,OAAvB;AACA,OAAO,KAAKC,SAAZ,MAA2B,aAA3B;AAIA;AACA,MAAMC,iBAAiB,GAAG;AACtB,GAACD,SAAS,CAACE,gBAAX,GAA8B,kBADR;AAEtB,GAACF,SAAS,CAACG,iBAAX,GAA+B,mBAFT;AAGtB,GAACH,SAAS,CAACI,cAAX,GAA4B;AAHN,CAA1B;AAOA,MAAMC,qBAAqB,GAAG;AAC1B,GAACL,SAAS,CAACM,QAAX,GAAsB,UADI;AAE1B,GAACN,SAAS,CAACO,iBAAX,GAA+B,mBAFL;AAG1B,GAACP,SAAS,CAACQ,aAAX,GAA2B;AAHD,CAA9B;AAOA,MAAMC,uBAAuB,GAAG;AAC5B,GAACT,SAAS,CAACU,iBAAX,GAA+B,mBADH;AAE5B,GAACV,SAAS,CAACW,gBAAX,GAA8B,kBAFF;AAG5B,GAACX,SAAS,CAACY,mBAAX,GAAiC;AAHL,CAAhC","sourcesContent":["// @flow\nimport * as React from 'react';\nimport * as constants from './constants';\nimport type { BoxItemPermission, ItemType } from '../../common/types/core';\nimport type { TargetingApi } from '../targeting/types';\n\n// DRY: Invert the constants so that we can construct the appropriate enum types\nconst accessLevelValues = {\n [constants.ANYONE_WITH_LINK]: 'ANYONE_WITH_LINK',\n [constants.ANYONE_IN_COMPANY]: 'ANYONE_IN_COMPANY',\n [constants.PEOPLE_IN_ITEM]: 'PEOPLE_IN_ITEM',\n};\nexport type accessLevelType = $Keys<typeof accessLevelValues>;\n\nconst permissionLevelValues = {\n [constants.CAN_EDIT]: 'CAN_EDIT',\n [constants.CAN_VIEW_DOWNLOAD]: 'CAN_VIEW_DOWNLOAD',\n [constants.CAN_VIEW_ONLY]: 'CAN_VIEW_ONLY',\n};\nexport type permissionLevelType = $Keys<typeof permissionLevelValues>;\n\nconst collaboratorGroupValues = {\n [constants.COLLAB_GROUP_TYPE]: 'COLLAB_GROUP_TYPE',\n [constants.COLLAB_USER_TYPE]: 'COLLAB_USER_TYPE',\n [constants.COLLAB_PENDING_TYPE]: 'COLLAB_PENDING_TYPE',\n};\nexport type collaboratorGroupType = $Keys<typeof collaboratorGroupValues>;\n\nexport type allowedAccessLevelsType = {\n peopleInThisItem?: boolean,\n peopleInYourCompany?: boolean,\n peopleWithTheLink?: boolean,\n};\n\nexport type accessLevelsDisabledReasonType = {\n peopleInThisItem?:\n | typeof constants.DISABLED_REASON_ACCESS_POLICY\n | typeof constants.DISABLED_REASON_MALICIOUS_CONTENT\n | null,\n peopleInYourCompany?:\n | typeof constants.DISABLED_REASON_ACCESS_POLICY\n | typeof constants.DISABLED_REASON_MALICIOUS_CONTENT\n | null,\n peopleWithTheLink?:\n | typeof constants.DISABLED_REASON_ACCESS_POLICY\n | typeof constants.DISABLED_REASON_MALICIOUS_CONTENT\n | null,\n};\n\nexport type contactType = {\n email?: string,\n id: string,\n isExternalUser?: boolean,\n name?: string,\n text?: string,\n type: string,\n value?: string,\n};\n\nexport type SuggestedCollab = contactType & {\n userScore: number,\n};\n\nexport type SuggestedCollabLookup = {\n [id: string]: SuggestedCollab,\n};\n\nexport type inviteePermissionType = {\n default: boolean,\n disabled?: boolean,\n text: string,\n value: string,\n};\n\nexport type item = {\n bannerPolicy?: {\n body: string,\n colorID?: number,\n title?: string,\n },\n canUserSeeClassification: boolean,\n classification?: string,\n description: string,\n extension: string,\n grantedPermissions: {\n itemShare: boolean,\n },\n hideCollaborators: boolean,\n id: string,\n name: string,\n ownerEmail?: string,\n ownerID?: string,\n permissions?: BoxItemPermission,\n type: ItemType,\n typedID: string,\n};\n\nexport type emailFormTrackingType = {\n cancelButtonProps?: Object,\n messageProps?: Object,\n onContactAdd?: Function,\n onContactRemove?: Function,\n onSendClick?: Function,\n};\n\nexport type sharedLinkTrackingType = {\n copyButtonProps?: Object,\n onChangeSharedLinkAccessLevel?: Function,\n onChangeSharedLinkPermissionLevel?: Function,\n onSharedLinkAccessMenuOpen?: Function,\n onSharedLinkCopy?: Function,\n onToggleLink?: Function,\n sendSharedLinkButtonProps?: Object,\n sharedLinkAccessMenuButtonProps?: Object,\n sharedLinkPermissionsMenuButtonProps?: Object,\n sharedLinkSettingsButtonProps?: Object,\n};\n\nexport type collaboratorListTrackingType = {\n doneButtonProps?: Object,\n emailProps?: Object,\n manageLinkProps?: Object,\n usernameProps?: Object,\n viewAdditionalProps?: Object,\n};\n\nexport type trackingPropsType = {\n collaboratorListTracking: collaboratorListTrackingType,\n inviteCollabTracking: {\n inviteePermissionsButtonProps?: Object,\n onEnterInviteCollabs?: Function,\n onInviteePermissionChange?: Function,\n },\n inviteCollabsEmailTracking: {\n ...emailFormTrackingType,\n upgradeLinkProps?: Object,\n },\n modalTracking: {\n collaboratorAvatarsProps?: Object,\n ftuxConfirmButtonProps?: Object,\n modalProps?: Object,\n onLoad?: Function,\n onLoadSharedLink?: Function,\n },\n removeLinkConfirmModalTracking: {\n cancelButtonProps?: Object,\n modalProps?: Object,\n okayButtonProps?: Object,\n onLoad?: Function,\n },\n sharedLinkEmailTracking: emailFormTrackingType,\n sharedLinkTracking: sharedLinkTrackingType,\n};\n\n// this type is a strict subset of the SharedLinkRecord data returned from the server\nexport type sharedLinkType = {\n accessLevel: accessLevelType,\n accessLevelsDisabledReason?: accessLevelsDisabledReasonType,\n allowedAccessLevels: allowedAccessLevelsType,\n canChangeAccessLevel: boolean,\n enterpriseName: string,\n expirationTimestamp: ?number,\n isDownloadAllowed: boolean,\n isDownloadSettingAvailable: boolean,\n isEditAllowed: boolean,\n isEditSettingAvailable: boolean,\n isNewSharedLink: boolean,\n isPreviewAllowed: boolean,\n permissionLevel: permissionLevelType,\n url: string,\n};\n\nexport type collaboratorType = {\n collabID: number,\n email?: string,\n expiration?: {\n executeAt: string,\n },\n hasCustomAvatar: boolean,\n imageURL: ?string,\n isExternalCollab?: boolean,\n name: string,\n type: collaboratorGroupType,\n userID: ?number,\n};\n\nexport type collaboratorsListType = {\n collaborators: Array<collaboratorType>,\n};\n\nexport type tooltipComponentIdentifierType =\n | 'shared-link-access-menu'\n | 'shared-link-copy-button'\n | 'shared-link-settings'\n | 'shared-link-toggle';\n\nexport type justificationCheckpointType =\n | typeof constants.JUSTIFICATION_CHECKPOINT_COLLAB\n | typeof constants.JUSTIFICATION_CHECKPOINT_CREATE_SHARED_LINK\n | typeof constants.JUSTIFICATION_CHECKPOINT_DOWNLOAD\n | typeof constants.JUSTIFICATION_CHECKPOINT_EXTERNAL_COLLAB;\n\nexport type justificationReasonType = {\n description?: string,\n id: string,\n isDetailsRequired?: boolean,\n title: string,\n};\nexport type getJustificationReasonsResponseType = {\n classificationLabelId: string,\n options?: Array<justificationReasonType>,\n};\n\n// Prop types used in the invite section of the Unified Share Form\ntype InviteSectionTypes = {\n /** Message warning about restrictions regarding inviting collaborators to the item */\n collaborationRestrictionWarning: React.Node,\n /** Used to limit the number of contacts that can be added in the contacts field */\n contactLimit?: number,\n /** Handler function for when the user types into invite collaborators field to fetch contacts. */\n getCollaboratorContacts: (query: string) => Promise<Array<contactType>>,\n /** Shows a callout tooltip next to the names / email addresses input field explaining pre-populated recommendation */\n recommendedSharingTooltipCalloutName: ?string,\n /**\n * Function to send collab invitations based on the given parameters object.\n * This function should return a Promise.\n */\n sendInvites: (params: Object) => Promise<Object>,\n /** Message indicating an error occurred while sending the invites. */\n sendInvitesError: React.Node,\n /** Function hoists contact data upon updates to the parent component. Only needed for suggested collabs. */\n setUpdatedContacts?: (inviteCollabsContacts: Array<contactType>) => void,\n /** Determine whether to show the First-time experience tooltip on load */\n showCalloutForUser?: boolean,\n /**\n * Flag to show link to upgrade and get more access controls.\n * Only applicable to non-file item types.\n */\n showUpgradeOptions: boolean,\n /** Data for suggested collaborators shown at bottom of input box. UI doesn't render when this has length of 0. */\n suggestedCollaborators?: SuggestedCollabLookup,\n};\n\n// Additional invite section types that related with information barrier, external collab\n// restrictions and business justifications.\nexport type CollabRestrictionType =\n | typeof constants.COLLAB_RESTRICTION_TYPE_ACCESS_POLICY\n | typeof constants.COLLAB_RESTRICTION_TYPE_INFORMATION_BARRIER;\n\ntype CollabRestrictionsTypes = {\n /** The type of restriction that applies to restrictedCollabEmails */\n collabRestrictionType?: CollabRestrictionType,\n /** Function that fetches the array of justification reason options to display on the justification select field */\n getJustificationReasons?: (\n itemTypedID: string,\n checkpoint: justificationCheckpointType,\n ) => Promise<getJustificationReasonsResponseType>,\n /** Determines whether or not a business justification can be provided to bypass external collab restrictions */\n isCollabRestrictionJustificationAllowed?: boolean,\n /** Function that is called when all restricted collaborators are removed from the email form */\n onRemoveAllRestrictedCollabs?: () => void,\n /** An array of all the collab email addresses that have been determined to be restricted by a security policy. */\n restrictedCollabEmails: Array<string>,\n /** An array of all the group ids that have been determined to be restricted by a security policy. */\n restrictedGroups: Array<number>,\n};\n\n// Prop types used in the shared link section of the Unified Share Form\n// (Note: while there is an overlap between these types and the props passed to the Shared Link Section component,\n// they are different. See the render() function of the Unified Share Form for details.)\ntype SharedLinkSectionTypes = {\n /** Handler function that changes shared link access level */\n changeSharedLinkAccessLevel: (newAccessLevel: accessLevelType) => Promise<{ accessLevel: accessLevelType }>,\n /** Handler function that changes shared link permission level */\n changeSharedLinkPermissionLevel: (\n newPermissionLevel: permissionLevelType,\n ) => Promise<{ permissionLevel: permissionLevelType }>,\n /** Whether the form should create a shared link on load */\n createSharedLinkOnLoad?: boolean,\n /** Handler function that adds the shared link */\n onAddLink: () => void,\n /** Handler for when there is an error copying to clipboard */\n onCopyError?: () => void,\n /** Handler for when we initiate copying from to clipboard */\n onCopyInit?: () => void,\n /** Handler for when successfully copying to clipboard */\n onCopySuccess?: () => void,\n /** Handler function that gets called whenever the user dismisses a tooltip on the given component identifier */\n onDismissTooltip?: (componentIdentifier: tooltipComponentIdentifierType) => void,\n /** Handler function for clicks on the settings button. If not provided, the settings button won't be rendered. */\n onSettingsClick?: Function,\n /** Shared link data */\n sharedLink: sharedLinkType,\n /** Shows a callout tooltip next to settings button with info about what can be customized */\n showSharedLinkSettingsCallout?: boolean,\n /** Mapping of components to the content that should be rendered in their tooltips */\n tooltips?: { [componentIdentifier: tooltipComponentIdentifierType]: React.Node },\n};\n\n// Prop types used in the collaborator avatars section of the Unified Share Form\ntype CollaboratorAvatarsTypes = {\n /** List of existing collaborators */\n collaboratorsList?: collaboratorsListType,\n /** User ID of currently logged in user */\n currentUserID: string,\n};\n\ntype EmailFormTypes = {\n /** Function to retrieve the URL for an avatar, given contact details */\n getContactAvatarUrl?: (contact: contactType) => string,\n /** Handler function for when the user types into email shared link field to fetch contacts. */\n getSharedLinkContacts: (query: string) => Promise<Array<contactType>>,\n /**\n * Function to send shared link email based on the given parameters object.\n * This function should return a Promise.\n */\n sendSharedLink: (params: Object) => Promise<Object>,\n /** Message indicating an error occurred while sending the shared link. */\n sendSharedLinkError: React.Node,\n};\n\ntype AdvancedContentInsightsUSProps = {\n isAdvancedContentInsightsChecked?: boolean,\n /** Handler function that gets called whenever the Advanced Content Insights toggle changes */\n onAdvancedContentInsightsToggle?: Function,\n};\n\nexport type USMConfig = {\n /** Whether the \"Email Shared Link\" button and form should be rendered in the USM/USF */\n showEmailSharedLinkForm: boolean,\n /* Whether the message section of the invite collaborator page should be rendered in the USM/USF */\n showInviteCollaboratorMessageSection: boolean,\n};\n\n// Prop types shared by both the Unified Share Modal and the Unified Share Form\ntype BaseUnifiedShareProps = CollaboratorAvatarsTypes &\n AdvancedContentInsightsUSProps &\n EmailFormTypes &\n CollabRestrictionsTypes &\n InviteSectionTypes &\n SharedLinkSectionTypes & {\n /** Inline message */\n allShareRestrictionWarning?: React.Node,\n /** Flag to determine whether to enable invite collaborators section */\n canInvite: boolean,\n /** Configuration object for hiding parts of the USM */\n config?: USMConfig,\n /** Whether the full USM should be rendered */\n displayInModal?: boolean,\n /** Whether the form should focus the shared link after the URL is resolved */\n focusSharedLinkOnLoad?: boolean,\n /** Handler function that gets contacts by a list of emails */\n getContactsByEmail?: ({ emails: Array<string>, itemTypedID?: string }) => Promise<Object>,\n /** Handler function for getting intial data for form */\n getInitialData: Function,\n /** An array of initially selected contacts. If none are initially selected, an empty array. */\n initiallySelectedContacts: Array<contactType>,\n /** Intl object */\n intl: any,\n /** An array of invitee permissions */\n inviteePermissions: Array<inviteePermissionType>,\n /** Item data */\n item: item,\n /** Shows a callout tooltip next to the names / email addresses input field encouraging users to fill out coworkers contact info */\n showEnterEmailsCallout?: boolean,\n /** Whether or not a request is in progress */\n submitting: boolean,\n /** Object with props and handlers for tracking interactions */\n trackingProps: trackingPropsType,\n };\n\n// Prop types for the Unified Share Modal\nexport type USMProps = BaseUnifiedShareProps & {\n /** Function for closing the Remove Link Confirm Modal */\n closeConfirmModal: () => void,\n /** Whether initial data for the USM has already been received */\n initialDataReceived: boolean,\n /** Whether the allow edit shared link for file FF is enabled */\n isAllowEditSharedLinkForFileEnabled?: boolean,\n /** Whether the USM is open */\n isOpen?: boolean,\n /** Handler function that removes the shared link, used in the Remove Link Confirm Modal */\n onRemoveLink: () => void,\n /** Handler function for when the USM is closed */\n onRequestClose?: Function,\n /** Whether the FTUX tag should be rendered for the Can Edit option */\n sharedLinkEditTagTargetingApi?: TargetingApi,\n /** Whether the FTUX tooltip should be rendered for Editable Shared Links */\n sharedLinkEditTooltipTargetingApi?: TargetingApi,\n};\n\n// Prop types for the Unified Share Form, passed from the Unified Share Modal\nexport type USFProps = BaseUnifiedShareProps & {\n /** Function for closing the FTUX tooltip */\n handleFtuxCloseClick: () => void,\n /** Whether the allow edit shared link for file FF is enabled */\n isAllowEditSharedLinkForFileEnabled: boolean,\n /** Whether the data for the USM/USF is being fetched */\n isFetching: boolean,\n /** Function for opening the Remove Link Confirm Modal */\n openConfirmModal: () => void,\n /** Function for opening the Upgrade Plan Modal */\n openUpgradePlanModal: () => void,\n /** Whether the FTUX tag should be rendered for the Can Edit option */\n sharedLinkEditTagTargetingApi?: TargetingApi,\n /** Whether the FTUX tooltip should be rendered for Editable Shared Links */\n sharedLinkEditTooltipTargetingApi?: TargetingApi,\n /** Whether the shared link has loaded */\n sharedLinkLoaded: boolean,\n /** Whether the FTUX tooltip should be rendered */\n shouldRenderFTUXTooltip: boolean,\n /** Whether the upgrade inline notice should be rendered */\n showUpgradeInlineNotice?: boolean,\n};\n\nexport type InviteCollaboratorsRequest = {\n classificationLabelId?: string,\n emailMessage: string,\n emails: string,\n groupIDs: string,\n justificationReason?: justificationReasonType,\n numOfInviteeGroups: number,\n numsOfInvitees: number,\n permission: string,\n};\n"],"file":"flowTypes.js"}
|
|
1
|
+
{"version":3,"sources":["../../../src/features/unified-share-modal/flowTypes.js"],"names":["React","constants","accessLevelValues","ANYONE_WITH_LINK","ANYONE_IN_COMPANY","PEOPLE_IN_ITEM","permissionLevelValues","CAN_EDIT","CAN_VIEW_DOWNLOAD","CAN_VIEW_ONLY","collaboratorGroupValues","COLLAB_GROUP_TYPE","COLLAB_USER_TYPE","COLLAB_PENDING_TYPE"],"mappings":"AACA,OAAO,KAAKA,KAAZ,MAAuB,OAAvB;AACA,OAAO,KAAKC,SAAZ,MAA2B,aAA3B;AAIA;AACA,MAAMC,iBAAiB,GAAG;AACtB,GAACD,SAAS,CAACE,gBAAX,GAA8B,kBADR;AAEtB,GAACF,SAAS,CAACG,iBAAX,GAA+B,mBAFT;AAGtB,GAACH,SAAS,CAACI,cAAX,GAA4B;AAHN,CAA1B;AAOA,MAAMC,qBAAqB,GAAG;AAC1B,GAACL,SAAS,CAACM,QAAX,GAAsB,UADI;AAE1B,GAACN,SAAS,CAACO,iBAAX,GAA+B,mBAFL;AAG1B,GAACP,SAAS,CAACQ,aAAX,GAA2B;AAHD,CAA9B;AAOA,MAAMC,uBAAuB,GAAG;AAC5B,GAACT,SAAS,CAACU,iBAAX,GAA+B,mBADH;AAE5B,GAACV,SAAS,CAACW,gBAAX,GAA8B,kBAFF;AAG5B,GAACX,SAAS,CAACY,mBAAX,GAAiC;AAHL,CAAhC","sourcesContent":["// @flow\nimport * as React from 'react';\nimport * as constants from './constants';\nimport type { BoxItemPermission, ItemType } from '../../common/types/core';\nimport type { TargetingApi } from '../targeting/types';\n\n// DRY: Invert the constants so that we can construct the appropriate enum types\nconst accessLevelValues = {\n [constants.ANYONE_WITH_LINK]: 'ANYONE_WITH_LINK',\n [constants.ANYONE_IN_COMPANY]: 'ANYONE_IN_COMPANY',\n [constants.PEOPLE_IN_ITEM]: 'PEOPLE_IN_ITEM',\n};\nexport type accessLevelType = $Keys<typeof accessLevelValues>;\n\nconst permissionLevelValues = {\n [constants.CAN_EDIT]: 'CAN_EDIT',\n [constants.CAN_VIEW_DOWNLOAD]: 'CAN_VIEW_DOWNLOAD',\n [constants.CAN_VIEW_ONLY]: 'CAN_VIEW_ONLY',\n};\nexport type permissionLevelType = $Keys<typeof permissionLevelValues>;\n\nconst collaboratorGroupValues = {\n [constants.COLLAB_GROUP_TYPE]: 'COLLAB_GROUP_TYPE',\n [constants.COLLAB_USER_TYPE]: 'COLLAB_USER_TYPE',\n [constants.COLLAB_PENDING_TYPE]: 'COLLAB_PENDING_TYPE',\n};\nexport type collaboratorGroupType = $Keys<typeof collaboratorGroupValues>;\n\nexport type allowedAccessLevelsType = {\n peopleInThisItem?: boolean,\n peopleInYourCompany?: boolean,\n peopleWithTheLink?: boolean,\n};\n\nexport type accessLevelsDisabledReasonType = {\n peopleInThisItem?:\n | typeof constants.DISABLED_REASON_ACCESS_POLICY\n | typeof constants.DISABLED_REASON_MALICIOUS_CONTENT\n | null,\n peopleInYourCompany?:\n | typeof constants.DISABLED_REASON_ACCESS_POLICY\n | typeof constants.DISABLED_REASON_MALICIOUS_CONTENT\n | null,\n peopleWithTheLink?:\n | typeof constants.DISABLED_REASON_ACCESS_POLICY\n | typeof constants.DISABLED_REASON_MALICIOUS_CONTENT\n | null,\n};\n\nexport type contactType = {\n email?: string,\n id: string,\n isExternalUser?: boolean,\n name?: string,\n text?: string,\n type: string,\n value?: string,\n};\n\nexport type SuggestedCollab = contactType & {\n userScore: number,\n};\n\nexport type SuggestedCollabLookup = {\n [id: string]: SuggestedCollab,\n};\n\nexport type inviteePermissionType = {\n default: boolean,\n disabled?: boolean,\n text: string,\n value: string,\n};\n\nexport type item = {\n bannerPolicy?: {\n body: string,\n colorID?: number,\n title?: string,\n },\n canUserSeeClassification: boolean,\n classification?: string,\n description: string,\n extension: string,\n grantedPermissions: {\n itemShare: boolean,\n },\n hideCollaborators: boolean,\n id: string,\n name: string,\n ownerEmail?: string,\n ownerID?: string,\n permissions?: BoxItemPermission,\n type: ItemType,\n typedID: string,\n};\n\nexport type emailFormTrackingType = {\n cancelButtonProps?: Object,\n messageProps?: Object,\n onContactAdd?: Function,\n onContactRemove?: Function,\n onSendClick?: Function,\n};\n\nexport type sharedLinkTrackingType = {\n copyButtonProps?: Object,\n onChangeSharedLinkAccessLevel?: Function,\n onChangeSharedLinkPermissionLevel?: Function,\n onSharedLinkAccessMenuOpen?: Function,\n onSharedLinkCopy?: Function,\n onToggleLink?: Function,\n sendSharedLinkButtonProps?: Object,\n sharedLinkAccessMenuButtonProps?: Object,\n sharedLinkPermissionsMenuButtonProps?: Object,\n sharedLinkSettingsButtonProps?: Object,\n};\n\nexport type collaboratorListTrackingType = {\n doneButtonProps?: Object,\n emailProps?: Object,\n manageLinkProps?: Object,\n usernameProps?: Object,\n viewAdditionalProps?: Object,\n};\n\nexport type trackingPropsType = {\n collaboratorListTracking: collaboratorListTrackingType,\n inviteCollabTracking: {\n inviteePermissionsButtonProps?: Object,\n onEnterInviteCollabs?: Function,\n onInviteePermissionChange?: Function,\n },\n inviteCollabsEmailTracking: {\n ...emailFormTrackingType,\n upgradeLinkProps?: Object,\n },\n modalTracking: {\n collaboratorAvatarsProps?: Object,\n ftuxConfirmButtonProps?: Object,\n modalProps?: Object,\n onLoad?: Function,\n onLoadSharedLink?: Function,\n },\n removeLinkConfirmModalTracking: {\n cancelButtonProps?: Object,\n modalProps?: Object,\n okayButtonProps?: Object,\n onLoad?: Function,\n },\n sharedLinkEmailTracking: emailFormTrackingType,\n sharedLinkTracking: sharedLinkTrackingType,\n};\n\n// this type is a strict subset of the SharedLinkRecord data returned from the server\nexport type sharedLinkType = {\n accessLevel: accessLevelType,\n accessLevelsDisabledReason?: accessLevelsDisabledReasonType,\n allowedAccessLevels: allowedAccessLevelsType,\n canChangeAccessLevel: boolean,\n enterpriseName: string,\n expirationTimestamp: ?number,\n isDownloadAllowed: boolean,\n isDownloadSettingAvailable: boolean,\n isEditAllowed: boolean,\n isEditSettingAvailable: boolean,\n isNewSharedLink: boolean,\n isPreviewAllowed: boolean,\n permissionLevel: permissionLevelType,\n url: string,\n};\n\nexport type collaboratorType = {\n collabID: number,\n email?: string,\n expiration?: {\n executeAt: string,\n },\n hasCustomAvatar: boolean,\n imageURL: ?string,\n isExternalCollab?: boolean,\n name: string,\n type: collaboratorGroupType,\n userID: ?number,\n};\n\nexport type collaboratorsListType = {\n collaborators: Array<collaboratorType>,\n};\n\nexport type tooltipComponentIdentifierType =\n | 'shared-link-access-menu'\n | 'shared-link-copy-button'\n | 'shared-link-settings'\n | 'shared-link-toggle';\n\nexport type justificationCheckpointType =\n | typeof constants.JUSTIFICATION_CHECKPOINT_COLLAB\n | typeof constants.JUSTIFICATION_CHECKPOINT_CREATE_SHARED_LINK\n | typeof constants.JUSTIFICATION_CHECKPOINT_DOWNLOAD\n | typeof constants.JUSTIFICATION_CHECKPOINT_EXTERNAL_COLLAB;\n\nexport type justificationReasonType = {\n description?: string,\n id: string,\n isDetailsRequired?: boolean,\n title: string,\n};\nexport type getJustificationReasonsResponseType = {\n classificationLabelId: string,\n options?: Array<justificationReasonType>,\n};\n\n// Prop types used in the invite section of the Unified Share Form\ntype InviteSectionTypes = {\n /** Message warning about restrictions regarding inviting collaborators to the item */\n collaborationRestrictionWarning: React.Node,\n /** Used to limit the number of contacts that can be added in the contacts field */\n contactLimit?: number,\n /** Handler function for when the user types into invite collaborators field to fetch contacts. */\n getCollaboratorContacts: (query: string) => Promise<Array<contactType>>,\n /** Shows a callout tooltip next to the names / email addresses input field explaining pre-populated recommendation */\n recommendedSharingTooltipCalloutName: ?string,\n /**\n * Function to send collab invitations based on the given parameters object.\n * This function should return a Promise.\n */\n sendInvites: (params: Object) => Promise<Object>,\n /** Message indicating an error occurred while sending the invites. */\n sendInvitesError: React.Node,\n /** Function hoists contact data upon updates to the parent component. Only needed for suggested collabs. */\n setUpdatedContacts?: (inviteCollabsContacts: Array<contactType>) => void,\n /** Determine whether to show the First-time experience tooltip on load */\n showCalloutForUser?: boolean,\n /**\n * Flag to show link to upgrade and get more access controls.\n * Only applicable to non-file item types.\n */\n showUpgradeOptions: boolean,\n /** Data for suggested collaborators shown at bottom of input box. UI doesn't render when this has length of 0. */\n suggestedCollaborators?: SuggestedCollabLookup,\n};\n\n// Additional invite section types that related with information barrier, external collab\n// restrictions and business justifications.\nexport type CollabRestrictionType =\n | typeof constants.COLLAB_RESTRICTION_TYPE_ACCESS_POLICY\n | typeof constants.COLLAB_RESTRICTION_TYPE_INFORMATION_BARRIER;\n\ntype CollabRestrictionsTypes = {\n /** The type of restriction that applies to restrictedCollabEmails */\n collabRestrictionType?: CollabRestrictionType,\n /** Function that fetches the array of justification reason options to display on the justification select field */\n getJustificationReasons?: (\n itemTypedID: string,\n checkpoint: justificationCheckpointType,\n ) => Promise<getJustificationReasonsResponseType>,\n /** Determines whether or not a business justification can be provided to bypass external collab restrictions */\n isCollabRestrictionJustificationAllowed?: boolean,\n /** Function that is called when all restricted collaborators are removed from the email form */\n onRemoveAllRestrictedCollabs?: () => void,\n /** An array of all the collab email addresses that have been determined to be restricted by a security policy. */\n restrictedCollabEmails: Array<string>,\n /** An array of all the group ids that have been determined to be restricted by a security policy. */\n restrictedGroups: Array<number>,\n};\n\n// Prop types used in the shared link section of the Unified Share Form\n// (Note: while there is an overlap between these types and the props passed to the Shared Link Section component,\n// they are different. See the render() function of the Unified Share Form for details.)\ntype SharedLinkSectionTypes = {\n /** Handler function that changes shared link access level */\n changeSharedLinkAccessLevel: (newAccessLevel: accessLevelType) => Promise<{ accessLevel: accessLevelType }>,\n /** Handler function that changes shared link permission level */\n changeSharedLinkPermissionLevel: (\n newPermissionLevel: permissionLevelType,\n ) => Promise<{ permissionLevel: permissionLevelType }>,\n /** Whether the form should create a shared link on load */\n createSharedLinkOnLoad?: boolean,\n /** Handler function that adds the shared link */\n onAddLink: () => void,\n /** Handler for when there is an error copying to clipboard */\n onCopyError?: () => void,\n /** Handler for when we initiate copying from to clipboard */\n onCopyInit?: () => void,\n /** Handler for when successfully copying to clipboard */\n onCopySuccess?: () => void,\n /** Handler function that gets called whenever the user dismisses a tooltip on the given component identifier */\n onDismissTooltip?: (componentIdentifier: tooltipComponentIdentifierType) => void,\n /** Handler function for clicks on the settings button. If not provided, the settings button won't be rendered. */\n onSettingsClick?: Function,\n /** Shared link data */\n sharedLink: sharedLinkType,\n /** Shows a callout tooltip next to settings button with info about what can be customized */\n showSharedLinkSettingsCallout?: boolean,\n /** Mapping of components to the content that should be rendered in their tooltips */\n tooltips?: { [componentIdentifier: tooltipComponentIdentifierType]: React.Node },\n};\n\n// Prop types used in the collaborator avatars section of the Unified Share Form\ntype CollaboratorAvatarsTypes = {\n /** List of existing collaborators */\n collaboratorsList?: collaboratorsListType,\n /** User ID of currently logged in user */\n currentUserID: string,\n};\n\ntype EmailFormTypes = {\n /** Function to retrieve the URL for an avatar, given contact details */\n getContactAvatarUrl?: (contact: contactType) => string,\n /** Handler function for when the user types into email shared link field to fetch contacts. */\n getSharedLinkContacts: (query: string) => Promise<Array<contactType>>,\n /**\n * Function to send shared link email based on the given parameters object.\n * This function should return a Promise.\n */\n sendSharedLink: (params: Object) => Promise<Object>,\n /** Message indicating an error occurred while sending the shared link. */\n sendSharedLinkError: React.Node,\n};\n\ntype AdvancedContentInsightsUSProps = {\n isAdvancedContentInsightsChecked?: boolean,\n /** Handler function that gets called whenever the Advanced Content Insights toggle changes */\n onAdvancedContentInsightsToggle?: Function,\n};\n\nexport type USMConfig = {\n /** Whether the \"Email Shared Link\" button and form should be rendered in the USM/USF */\n showEmailSharedLinkForm: boolean,\n /* Whether the message section of the invite collaborator page should be rendered in the USM/USF */\n showInviteCollaboratorMessageSection: boolean,\n};\n\n// Prop types shared by both the Unified Share Modal and the Unified Share Form\ntype BaseUnifiedShareProps = CollaboratorAvatarsTypes &\n AdvancedContentInsightsUSProps &\n EmailFormTypes &\n CollabRestrictionsTypes &\n InviteSectionTypes &\n SharedLinkSectionTypes & {\n /** Inline message */\n allShareRestrictionWarning?: React.Node,\n /** Flag to determine whether to enable invite collaborators section */\n canInvite: boolean,\n /** Configuration object for hiding parts of the USM */\n config?: USMConfig,\n /** Whether the full USM should be rendered */\n displayInModal?: boolean,\n /** Whether the form should focus the shared link after the URL is resolved */\n focusSharedLinkOnLoad?: boolean,\n /** Handler function that gets contacts by a list of emails */\n getContactsByEmail?: ({ emails: Array<string>, itemTypedID?: string }) => Promise<Object>,\n /** Handler function for getting intial data for form */\n getInitialData: Function,\n /** An array of initially selected contacts. If none are initially selected, an empty array. */\n initiallySelectedContacts: Array<contactType>,\n /** Intl object */\n intl: any,\n /** An array of invitee permissions */\n inviteePermissions: Array<inviteePermissionType>,\n /** Item data */\n item: item,\n /** Shows a callout tooltip next to the names / email addresses input field encouraging users to fill out coworkers contact info */\n showEnterEmailsCallout?: boolean,\n /** Whether or not a request is in progress */\n submitting: boolean,\n /** Object with props and handlers for tracking interactions */\n trackingProps: trackingPropsType,\n };\n\n// Prop types for the Unified Share Modal\nexport type USMProps = BaseUnifiedShareProps & {\n /** Function for closing the Remove Link Confirm Modal */\n closeConfirmModal: () => void,\n /** Whether initial data for the USM has already been received */\n initialDataReceived: boolean,\n /** Whether the allow edit shared link for file FF is enabled */\n isAllowEditSharedLinkForFileEnabled?: boolean,\n /** Whether the USM is open */\n isOpen?: boolean,\n /** Handler function that removes the shared link, used in the Remove Link Confirm Modal */\n onRemoveLink: () => void,\n /** Handler function for when the USM is closed */\n onRequestClose?: Function,\n /** Whether the FTUX tag should be rendered for the Can Edit option */\n sharedLinkEditTagTargetingApi?: TargetingApi,\n /** Whether the FTUX tooltip should be rendered for Editable Shared Links */\n sharedLinkEditTooltipTargetingApi?: TargetingApi,\n};\n\n// Prop types for the Unified Share Form, passed from the Unified Share Modal\nexport type USFProps = BaseUnifiedShareProps & {\n /** Function for closing the FTUX tooltip */\n handleFtuxCloseClick: () => void,\n /** Whether the allow edit shared link for file FF is enabled */\n isAllowEditSharedLinkForFileEnabled: boolean,\n /** Whether the data for the USM/USF is being fetched */\n isFetching: boolean,\n /** Function for opening the Remove Link Confirm Modal */\n openConfirmModal: () => void,\n /** Function for opening the Upgrade Plan Modal */\n openUpgradePlanModal: () => void,\n /** Whether the FTUX tag should be rendered for the Can Edit option */\n sharedLinkEditTagTargetingApi?: TargetingApi,\n /** Whether the FTUX tooltip should be rendered for Editable Shared Links */\n sharedLinkEditTooltipTargetingApi?: TargetingApi,\n /** Whether the shared link has loaded */\n sharedLinkLoaded: boolean,\n /** Whether the FTUX tooltip should be rendered */\n shouldRenderFTUXTooltip: boolean,\n /** Whether the upgrade inline notice should be rendered\n * NOTE (wyehdego): Remove this prop once we refactor legacy inline notice with upsellInlineNotice\n */\n showUpgradeInlineNotice?: boolean,\n /** Inline Notice component to render based on user */\n upsellInlineNotice?: React.Node | null,\n};\n\nexport type InviteCollaboratorsRequest = {\n classificationLabelId?: string,\n emailMessage: string,\n emails: string,\n groupIDs: string,\n justificationReason?: justificationReasonType,\n numOfInviteeGroups: number,\n numsOfInvitees: number,\n permission: string,\n};\n"],"file":"flowTypes.js"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "box-ui-elements",
|
|
3
|
-
"version": "20.0.0
|
|
3
|
+
"version": "20.0.0",
|
|
4
4
|
"description": "Box UI Elements",
|
|
5
5
|
"author": "Box (https://www.box.com/)",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"copy:flow": "flow-copy-source --ignore \"**/__tests__/**\" --ignore \"**/__mocks__/**\" --ignore \"**/*.ts\" ./src ./es && copyfiles './src/**/*.js.flow' es --up 1",
|
|
61
61
|
"copy:styles": "copyfiles './src/**/*.scss' es --up 1",
|
|
62
62
|
"cy:open": "yarn cy:wait; yarn cypress open",
|
|
63
|
-
"cy:run": "yarn cy:wait; yarn cypress run --spec \"test/integration/**/*.
|
|
63
|
+
"cy:run": "yarn cy:wait; yarn cypress run --spec \"test/integration/**/*.cy.js\"",
|
|
64
64
|
"cy:wait": "wait-on http-get://127.0.0.1:6060/#",
|
|
65
65
|
"lint": "npm-run-all lint:*",
|
|
66
66
|
"lint:js": "eslint --max-warnings=0 .",
|
|
@@ -242,7 +242,7 @@
|
|
|
242
242
|
"cosmiconfig": "^6.0.0",
|
|
243
243
|
"css-loader": "^3.4.2",
|
|
244
244
|
"cssnano": "^4.1.10",
|
|
245
|
-
"cypress": "
|
|
245
|
+
"cypress": "^13.7.3",
|
|
246
246
|
"deepmerge": "^4.2.2",
|
|
247
247
|
"draft-js": "^0.10.1",
|
|
248
248
|
"enzyme": "^3.11.0",
|
|
@@ -251,7 +251,7 @@
|
|
|
251
251
|
"eslint-config-airbnb": "^18.0.1",
|
|
252
252
|
"eslint-config-prettier": "^6.9.0",
|
|
253
253
|
"eslint-plugin-babel": "^5.3.0",
|
|
254
|
-
"eslint-plugin-cypress": "^2.
|
|
254
|
+
"eslint-plugin-cypress": "^2.15.1",
|
|
255
255
|
"eslint-plugin-flowtype": "^4.6.0",
|
|
256
256
|
"eslint-plugin-formatjs": "^1.5.11",
|
|
257
257
|
"eslint-plugin-import": "^2.19.1",
|
|
@@ -378,10 +378,10 @@
|
|
|
378
378
|
"mousetrap": "^1.6.3",
|
|
379
379
|
"pikaday": "^1.8.0",
|
|
380
380
|
"query-string": "5.1.1",
|
|
381
|
-
"react": "^17.0.1
|
|
381
|
+
"react": "^17.0.1",
|
|
382
382
|
"react-animate-height": "^2.0.8",
|
|
383
383
|
"react-beautiful-dnd": "^13.1.1",
|
|
384
|
-
"react-dom": "^17.0.1
|
|
384
|
+
"react-dom": "^17.0.1",
|
|
385
385
|
"react-draggable": "^3.3.0",
|
|
386
386
|
"react-immutable-proptypes": "^2.1.0",
|
|
387
387
|
"react-intl": ">=2.9.0",
|
|
@@ -392,7 +392,7 @@
|
|
|
392
392
|
"react-responsive": "8.2.0",
|
|
393
393
|
"react-router-dom": "^5.0.0",
|
|
394
394
|
"react-scrollbars-custom": "^4.0.21",
|
|
395
|
-
"react-tether": "1.0.
|
|
395
|
+
"react-tether": "^1.0.0",
|
|
396
396
|
"react-textarea-autosize": "^8.5.3",
|
|
397
397
|
"regenerator-runtime": "^0.13.2",
|
|
398
398
|
"sanitize-html": "1.21.1",
|
package/src/constants.js
CHANGED
|
@@ -179,7 +179,7 @@ export const DELIMITER_SLASH: 'slash' = 'slash';
|
|
|
179
179
|
export const DELIMITER_CARET: 'caret' = 'caret';
|
|
180
180
|
|
|
181
181
|
/* ---------------------- Defaults -------------------------- */
|
|
182
|
-
export const DEFAULT_PREVIEW_VERSION = '2.
|
|
182
|
+
export const DEFAULT_PREVIEW_VERSION = '2.106.0';
|
|
183
183
|
export const DEFAULT_LOCALE = 'en-US';
|
|
184
184
|
export const DEFAULT_PATH_STATIC = 'platform/elements';
|
|
185
185
|
export const DEFAULT_PATH_STATIC_PREVIEW = 'platform/preview';
|
package/src/elements/README.md
CHANGED
|
@@ -4,8 +4,43 @@ The Box UI Elements are designed to be agnostic of the authentication type. They
|
|
|
4
4
|
_Note: When you are required to pass an access token to a Box Element Component, keep in mind that you can pass the access token as a string, or as a function. If you pass a function, it should return a string. Whenever the Box Element Component needs to make an API call to Box, it will use the accessToken you supplied, or invoke the access token function to get the access token._
|
|
5
5
|
|
|
6
6
|
## Internationalization (i18n)
|
|
7
|
-
The UI Elements use [react-intl](https://
|
|
7
|
+
The UI Elements use [react-intl](https://formatjs.io/docs/react-intl/) for internationalization. In order for the UI Elements to render properly, they need to be wrapped in an i18n context via the [IntlProvider](https://github.com/formatjs/formatjs/blob/main/website/docs/react-intl/components.md#intlprovider) and given a locale and translated messages to use. Each of the UI Element components optionally take in a `language` property and a `messages` property which is then delegated to our internal [IntlProvider](src/components/Internationalize.js). If either of these properties are not passed in, we do not use our internal `IntlProvider` and it is assumed that the parent react app (the react app that is importing in the UI Elements) has its own `IntlProvider`.
|
|
8
8
|
|
|
9
9
|
The `language` property is a string that can be one of `en-AU`, `en-CA`, `en-GB`, `en-US`, `bn-IN`, `da-DK`, `de-DE`, `es-419`, `es-ES`, `fi-FI`, `fr-CA`, `fr-FR`, `hi-IN`, `it-IT`, `ja-JP`, `ko-KR`, `nb-NO`, `nl-NL`, `pl-PL`, `pt-BR`, `ru-RU`, `sv-SE`, `tr-TR`, `zh-CN`, `zh-TW`.
|
|
10
10
|
|
|
11
|
-
The `messages` property is a map of message keys and translated strings. All the messages that the UI elements use can be found under the [i18n](i18n) folder. We distribute them as JS modules within the `box-ui-elements` npm package and they can be imported like any other module - `import box-ui-elements/i18n/[LANGUAGE FROM ABOVE]`. The code examples for each of the UI Elements assume `en-US` and show how the US english messages are imported in.
|
|
11
|
+
The `messages` property is a map of message keys and translated strings. All the messages that the UI elements use can be found under the [i18n](https://github.com/box/box-ui-elements/tree/master/i18n) folder. We distribute them as JS modules within the `box-ui-elements` npm package and they can be imported like any other module - `import box-ui-elements/i18n/[LANGUAGE FROM ABOVE]`. The code examples for each of the UI Elements assume `en-US` and show how the US english messages are imported in.
|
|
12
|
+
|
|
13
|
+
If you are using the CDNs, the i18n messages are included in the bundle.
|
|
14
|
+
|
|
15
|
+
Example of using the `language` and `messages` properties:
|
|
16
|
+
```jsx
|
|
17
|
+
import messages from 'box-ui-elements/i18n/ja-JP';
|
|
18
|
+
|
|
19
|
+
<ContentExplorer language="ja-JP" messages={messages} {...PROPS} />
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
_ContentExplorer will show in Japanese._
|
|
23
|
+
|
|
24
|
+
Example `IntlProvider` with multiple elements
|
|
25
|
+
```jsx
|
|
26
|
+
import messages from 'box-ui-elements/i18n/ja-JP';
|
|
27
|
+
|
|
28
|
+
<IntlProvider locale="ja-JP" messages={messages}>
|
|
29
|
+
<ContentExplorer {...PROPS} />
|
|
30
|
+
<ContentPicker {...PROPS} />
|
|
31
|
+
</IntlProvider>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
_Both ContentExplorer and ContentPicker will show in Japanese._
|
|
35
|
+
|
|
36
|
+
Example of using different `language` and `messages` properties:
|
|
37
|
+
|
|
38
|
+
```jsx
|
|
39
|
+
import jaMessages from 'box-ui-elements/i18n/ja-JP';
|
|
40
|
+
import deMessages from 'box-ui-elements/i18n/de-DE';
|
|
41
|
+
|
|
42
|
+
<ContentExplorer language="ja-JP" messages={jaMessages} {...PROPS} />
|
|
43
|
+
<ContentPicker language="de-DE" messages={deMessages} {...PROPS} />
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
_ContentExplorer will show in Japanese and ContentPicker will show in German._
|
|
@@ -8,7 +8,7 @@ import Fieldset from '../../components/fieldset';
|
|
|
8
8
|
|
|
9
9
|
import messages from './messages';
|
|
10
10
|
|
|
11
|
-
const
|
|
11
|
+
export const defaultDisplayFormat = {
|
|
12
12
|
weekday: 'short',
|
|
13
13
|
year: 'numeric',
|
|
14
14
|
month: 'short',
|
|
@@ -18,6 +18,7 @@ const displayFormat = {
|
|
|
18
18
|
const ExpirationSection = ({
|
|
19
19
|
canChangeExpiration,
|
|
20
20
|
dateFormat,
|
|
21
|
+
dateDisplayFormat = defaultDisplayFormat,
|
|
21
22
|
error,
|
|
22
23
|
expirationCheckboxProps = {},
|
|
23
24
|
expirationDate,
|
|
@@ -31,7 +32,7 @@ const ExpirationSection = ({
|
|
|
31
32
|
<div>
|
|
32
33
|
<DatePicker
|
|
33
34
|
dateFormat={dateFormat}
|
|
34
|
-
displayFormat={
|
|
35
|
+
displayFormat={dateDisplayFormat}
|
|
35
36
|
error={error}
|
|
36
37
|
hideLabel
|
|
37
38
|
inputProps={expirationInputProps}
|
|
@@ -65,6 +66,7 @@ const ExpirationSection = ({
|
|
|
65
66
|
|
|
66
67
|
ExpirationSection.propTypes = {
|
|
67
68
|
canChangeExpiration: PropTypes.bool.isRequired,
|
|
69
|
+
dateDisplayFormat: PropTypes.object,
|
|
68
70
|
/** The format of the date value for form submit */
|
|
69
71
|
dateFormat: PropTypes.string,
|
|
70
72
|
error: PropTypes.string,
|
|
@@ -49,6 +49,8 @@ function getAccessNoticeMessageId(accessLevel, canDownload) {
|
|
|
49
49
|
|
|
50
50
|
class SharedLinkSettingsModal extends Component {
|
|
51
51
|
static propTypes = {
|
|
52
|
+
/* Pass dateDisplayFormat to define INTL timezone for formatting date for utc format */
|
|
53
|
+
dateDisplayFormat: PropTypes.object,
|
|
52
54
|
/** The format of the expiration date value for form submit */
|
|
53
55
|
dateFormat: PropTypes.string,
|
|
54
56
|
hideVanityNameSection: PropTypes.bool,
|
|
@@ -291,12 +293,19 @@ class SharedLinkSettingsModal extends Component {
|
|
|
291
293
|
}
|
|
292
294
|
|
|
293
295
|
renderExpirationSection() {
|
|
294
|
-
const {
|
|
296
|
+
const {
|
|
297
|
+
canChangeExpiration,
|
|
298
|
+
dateDisplayFormat,
|
|
299
|
+
dateFormat,
|
|
300
|
+
expirationCheckboxProps,
|
|
301
|
+
expirationInputProps,
|
|
302
|
+
} = this.props;
|
|
295
303
|
const { expirationDate, isExpirationEnabled, expirationError } = this.state;
|
|
296
304
|
|
|
297
305
|
return (
|
|
298
306
|
<ExpirationSection
|
|
299
307
|
canChangeExpiration={canChangeExpiration}
|
|
308
|
+
dateDisplayFormat={dateDisplayFormat}
|
|
300
309
|
dateFormat={dateFormat}
|
|
301
310
|
error={expirationError}
|
|
302
311
|
expirationCheckboxProps={expirationCheckboxProps}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import sinon from 'sinon';
|
|
3
3
|
|
|
4
|
-
import ExpirationSection from '../ExpirationSection';
|
|
4
|
+
import ExpirationSection, { defaultDisplayFormat } from '../ExpirationSection';
|
|
5
5
|
|
|
6
6
|
const sandbox = sinon.sandbox.create();
|
|
7
7
|
|
|
@@ -12,6 +12,13 @@ describe('features/shared-link-settings-modal/ExpirationSection', () => {
|
|
|
12
12
|
const onCheckboxChange = sandbox.stub();
|
|
13
13
|
const onExpirationDateChange = sandbox.stub();
|
|
14
14
|
|
|
15
|
+
const dateDisplayFormat = {
|
|
16
|
+
day: 'numeric',
|
|
17
|
+
month: 'long',
|
|
18
|
+
year: 'numeric',
|
|
19
|
+
timeZone: 'Europe/Warsaw',
|
|
20
|
+
};
|
|
21
|
+
|
|
15
22
|
const getWrapper = (props = {}) =>
|
|
16
23
|
shallow(
|
|
17
24
|
<ExpirationSection
|
|
@@ -104,5 +111,19 @@ describe('features/shared-link-settings-modal/ExpirationSection', () => {
|
|
|
104
111
|
|
|
105
112
|
expect(wrapper.prop('dateFormat')).toEqual(dateFormat);
|
|
106
113
|
});
|
|
114
|
+
|
|
115
|
+
test('should use default displayFormat in DatePicker when dateDisplayFormat not defined', () => {
|
|
116
|
+
const wrapper = getSubsection();
|
|
117
|
+
|
|
118
|
+
expect(wrapper.prop('displayFormat')).toEqual(defaultDisplayFormat);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test('should pass dateDisplayFormat to DatePicker displayFormat', () => {
|
|
122
|
+
const wrapper = getSubsection({
|
|
123
|
+
dateDisplayFormat,
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
expect(wrapper.prop('displayFormat')).toEqual(dateDisplayFormat);
|
|
127
|
+
});
|
|
107
128
|
});
|
|
108
129
|
});
|
|
@@ -26,6 +26,7 @@ describe('features/shared-link-settings-modal/SharedLinkSettingsModal', () => {
|
|
|
26
26
|
const isDirectLinkAvailable = true;
|
|
27
27
|
const isDirectLinkUnavailableDueToDownloadSettings = true;
|
|
28
28
|
const isDirectLinkUnavailableDueToAccessPolicy = true;
|
|
29
|
+
const isDirectLinkUnavailableDueToMaliciousContent = false;
|
|
29
30
|
|
|
30
31
|
const getWrapper = (props = {}) =>
|
|
31
32
|
shallow(
|
|
@@ -59,6 +60,7 @@ describe('features/shared-link-settings-modal/SharedLinkSettingsModal', () => {
|
|
|
59
60
|
isDirectLinkAvailable={isDirectLinkAvailable}
|
|
60
61
|
isDirectLinkUnavailableDueToDownloadSettings={isDirectLinkUnavailableDueToDownloadSettings}
|
|
61
62
|
isDirectLinkUnavailableDueToAccessPolicy={isDirectLinkUnavailableDueToAccessPolicy}
|
|
63
|
+
isDirectLinkUnavailableDueToMaliciousContent={isDirectLinkUnavailableDueToMaliciousContent}
|
|
62
64
|
{...props}
|
|
63
65
|
/>,
|
|
64
66
|
);
|
|
@@ -244,9 +246,16 @@ describe('features/shared-link-settings-modal/SharedLinkSettingsModal', () => {
|
|
|
244
246
|
test('should render an ExpirationSection', () => {
|
|
245
247
|
const dateFormat = 'utcTime';
|
|
246
248
|
const expirationDate = new Date('11/7/17');
|
|
249
|
+
const dateDisplayFormat = {
|
|
250
|
+
day: 'numeric',
|
|
251
|
+
month: 'long',
|
|
252
|
+
year: 'numeric',
|
|
253
|
+
timeZone: 'Europe/Warsaw',
|
|
254
|
+
};
|
|
247
255
|
|
|
248
256
|
const wrapper = getWrapper({
|
|
249
257
|
dateFormat,
|
|
258
|
+
dateDisplayFormat,
|
|
250
259
|
expirationTimestamp: 123,
|
|
251
260
|
});
|
|
252
261
|
|
|
@@ -260,6 +269,7 @@ describe('features/shared-link-settings-modal/SharedLinkSettingsModal', () => {
|
|
|
260
269
|
expect(section.length).toBe(1);
|
|
261
270
|
expect(section.prop('canChangeExpiration')).toEqual(canChangeExpiration);
|
|
262
271
|
expect(section.prop('dateFormat')).toEqual(dateFormat);
|
|
272
|
+
expect(section.prop('dateDisplayFormat')).toEqual(dateDisplayFormat);
|
|
263
273
|
expect(section.prop('expirationDate')).toEqual(expirationDate);
|
|
264
274
|
expect(section.prop('isExpirationEnabled')).toBe(true);
|
|
265
275
|
expect(section.prop('onCheckboxChange')).toEqual(wrapper.instance().onExpirationCheckboxChange);
|
|
@@ -438,6 +438,7 @@ class UnifiedShareForm extends React.Component<USFProps, State> {
|
|
|
438
438
|
submitting,
|
|
439
439
|
suggestedCollaborators,
|
|
440
440
|
trackingProps,
|
|
441
|
+
upsellInlineNotice,
|
|
441
442
|
} = this.props;
|
|
442
443
|
const { type } = item;
|
|
443
444
|
const { isFetchingJustificationReasons, isInviteSectionExpanded, justificationReasons } = this.state;
|
|
@@ -486,6 +487,7 @@ class UnifiedShareForm extends React.Component<USFProps, State> {
|
|
|
486
487
|
text: ftuxTooltipText,
|
|
487
488
|
theme: 'callout',
|
|
488
489
|
};
|
|
490
|
+
const showUpsellInlineNotice = !!upsellInlineNotice;
|
|
489
491
|
|
|
490
492
|
return (
|
|
491
493
|
<>
|
|
@@ -523,7 +525,10 @@ class UnifiedShareForm extends React.Component<USFProps, State> {
|
|
|
523
525
|
{...inviteCollabsEmailTracking}
|
|
524
526
|
>
|
|
525
527
|
{this.renderInviteePermissionsDropdown()}
|
|
526
|
-
{showUpgradeOptions &&
|
|
528
|
+
{showUpgradeOptions &&
|
|
529
|
+
!showUpgradeInlineNotice &&
|
|
530
|
+
!showUpsellInlineNotice &&
|
|
531
|
+
this.renderUpgradeLinkDescription()}
|
|
527
532
|
</EmailForm>
|
|
528
533
|
</div>
|
|
529
534
|
</Tooltip>
|
|
@@ -699,6 +704,7 @@ class UnifiedShareForm extends React.Component<USFProps, State> {
|
|
|
699
704
|
submitting,
|
|
700
705
|
tooltips = {},
|
|
701
706
|
trackingProps,
|
|
707
|
+
upsellInlineNotice = null,
|
|
702
708
|
} = this.props;
|
|
703
709
|
const { sharedLinkTracking, sharedLinkEmailTracking } = trackingProps;
|
|
704
710
|
const { isEmailLinkSectionExpanded, isInviteSectionExpanded, showCollaboratorList } = this.state;
|
|
@@ -712,6 +718,9 @@ class UnifiedShareForm extends React.Component<USFProps, State> {
|
|
|
712
718
|
<div className={displayInModal ? '' : 'be bdl-UnifiedShareForm'}>
|
|
713
719
|
<LoadingIndicatorWrapper isLoading={isFetching} hideContent>
|
|
714
720
|
{!hasExpandedSections && allShareRestrictionWarning}
|
|
721
|
+
|
|
722
|
+
{!!upsellInlineNotice && <div className="upsell-inline-notice">{upsellInlineNotice}</div>}
|
|
723
|
+
|
|
715
724
|
{showUpgradeOptions && showUpgradeInlineNotice && this.renderUpgradeInlineNotice()}
|
|
716
725
|
|
|
717
726
|
{!isEmailLinkSectionExpanded && !showCollaboratorList && this.renderInviteSection()}
|
|
@@ -73,6 +73,12 @@ describe('features/unified-share-modal/UnifiedShareForm', () => {
|
|
|
73
73
|
{...props}
|
|
74
74
|
/>,
|
|
75
75
|
);
|
|
76
|
+
const mockUpsellInlineNotice = (
|
|
77
|
+
<div>
|
|
78
|
+
<div className="upsell-title">Upsell Inline Notice</div>
|
|
79
|
+
<div className="upsell-body">Lorem Ipsum</div>
|
|
80
|
+
</div>
|
|
81
|
+
);
|
|
76
82
|
|
|
77
83
|
describe('render()', () => {
|
|
78
84
|
test('should render a default component with default props', () => {
|
|
@@ -205,14 +211,30 @@ describe('features/unified-share-modal/UnifiedShareForm', () => {
|
|
|
205
211
|
expect(wrapper).toMatchSnapshot();
|
|
206
212
|
});
|
|
207
213
|
|
|
208
|
-
test(
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
214
|
+
test.each([
|
|
215
|
+
[true, true, 'is not', null],
|
|
216
|
+
[true, false, 'is not', null],
|
|
217
|
+
[false, true, 'is not', null],
|
|
218
|
+
[false, false, 'is not', null],
|
|
219
|
+
[true, true, 'is', mockUpsellInlineNotice],
|
|
220
|
+
[true, false, 'is', mockUpsellInlineNotice],
|
|
221
|
+
[false, true, 'is', mockUpsellInlineNotice],
|
|
222
|
+
[false, false, 'is', mockUpsellInlineNotice],
|
|
223
|
+
])(
|
|
224
|
+
'should render a default component with upgrade CTA when showUpgradeInlineNotice is %s, showUpgradeOptions is %s, and upsellInlineNotice %s passed in',
|
|
225
|
+
(showUpgradeInlineNotice, showUpgradeOptions, upsellInlineNoticeDescription, upsellInlineNotice) => {
|
|
226
|
+
const wrapper = getWrapper({
|
|
227
|
+
canInvite: true,
|
|
228
|
+
isFetching: false,
|
|
229
|
+
showUpgradeInlineNotice,
|
|
230
|
+
showUpgradeOptions,
|
|
231
|
+
upsellInlineNotice,
|
|
232
|
+
});
|
|
233
|
+
expect(wrapper.exists('UpgradeBadge')).toBe(
|
|
234
|
+
showUpgradeOptions && !showUpgradeInlineNotice && !upsellInlineNotice,
|
|
235
|
+
);
|
|
236
|
+
},
|
|
237
|
+
);
|
|
216
238
|
|
|
217
239
|
test('should render correct upgrade inline notice when showUpgradeInlineNotice and showUpgradeOptions is enabled', () => {
|
|
218
240
|
const wrapper = getWrapper({
|
|
@@ -221,10 +243,23 @@ describe('features/unified-share-modal/UnifiedShareForm', () => {
|
|
|
221
243
|
showUpgradeInlineNotice: true,
|
|
222
244
|
showUpgradeOptions: true,
|
|
223
245
|
});
|
|
224
|
-
expect(wrapper.exists('UpgradeBadge')).toBe(false);
|
|
225
246
|
expect(wrapper.exists('InlineNotice')).toBe(true);
|
|
226
247
|
});
|
|
227
248
|
|
|
249
|
+
test('should render the upsell inline notice component when component is passed', () => {
|
|
250
|
+
const wrapper = getWrapper({ upsellInlineNotice: mockUpsellInlineNotice });
|
|
251
|
+
expect(wrapper.exists('.upsell-inline-notice')).toBe(true);
|
|
252
|
+
expect(wrapper.exists('.upsell-title')).toBe(true);
|
|
253
|
+
expect(wrapper.exists('.upsell-body')).toBe(true);
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
test('should not render the upsell inline notice div when component is passed', () => {
|
|
257
|
+
const wrapper = getWrapper();
|
|
258
|
+
expect(wrapper.exists('.upsell-inline-notice')).toBe(false);
|
|
259
|
+
expect(wrapper.exists('.upsell-title')).toBe(false);
|
|
260
|
+
expect(wrapper.exists('.upsell-body')).toBe(false);
|
|
261
|
+
});
|
|
262
|
+
|
|
228
263
|
test('should render a default component with correct Focus element and props when focusSharedLinkOnLoad is enabled', () => {
|
|
229
264
|
const wrapper = getWrapper({
|
|
230
265
|
focusSharedLinkOnLoad: true,
|
|
@@ -409,8 +409,12 @@ export type USFProps = BaseUnifiedShareProps & {
|
|
|
409
409
|
sharedLinkLoaded: boolean,
|
|
410
410
|
/** Whether the FTUX tooltip should be rendered */
|
|
411
411
|
shouldRenderFTUXTooltip: boolean,
|
|
412
|
-
/** Whether the upgrade inline notice should be rendered
|
|
412
|
+
/** Whether the upgrade inline notice should be rendered
|
|
413
|
+
* NOTE (wyehdego): Remove this prop once we refactor legacy inline notice with upsellInlineNotice
|
|
414
|
+
*/
|
|
413
415
|
showUpgradeInlineNotice?: boolean,
|
|
416
|
+
/** Inline Notice component to render based on user */
|
|
417
|
+
upsellInlineNotice?: React.Node | null,
|
|
414
418
|
};
|
|
415
419
|
|
|
416
420
|
export type InviteCollaboratorsRequest = {
|