Skip to content

Commit

Permalink
fix(content-uploader): resolve ItemAction issues (#3631)
Browse files Browse the repository at this point in the history
* fix: resolve ItemAction issues

* fix: unit tests

* fix: simplify loading indicator

---------

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
tjuanitas and mergify[bot] authored Sep 6, 2024
1 parent 0bee28b commit ba299b1
Show file tree
Hide file tree
Showing 15 changed files with 152 additions and 257 deletions.
2 changes: 2 additions & 0 deletions i18n/en-US.properties
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ be.close = Close
be.collaboratedFolder = Collaborated Folder
# Message to the user to collapse the Transcript entries
be.collapse = Collapse
# Label for complete state.
be.complete = Complete
# Text shown to users when opening the content insights flyout and there is an error
be.contentInsights.contentAnalyticsErrorText = There was a problem loading content insights. Please try again.
# Message shown when the user does not have access to view content insights anymore
Expand Down
5 changes: 5 additions & 0 deletions src/elements/common/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ const messages = defineMessages({
description: 'Message when new preview is available.',
defaultMessage: 'A new version of this file is available.',
},
complete: {
id: 'be.complete',
description: 'Label for complete state.',
defaultMessage: 'Complete',
},
loading: {
id: 'be.loading',
description: 'Label for loading state.',
Expand Down
18 changes: 0 additions & 18 deletions src/elements/content-uploader/IconInProgress.js

This file was deleted.

19 changes: 19 additions & 0 deletions src/elements/content-uploader/IconInProgress.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import * as React from 'react';
import { useIntl } from 'react-intl';
import { LoadingIndicator } from '@box/blueprint-web';
import { IconCtaIconHover, Size5 } from '@box/blueprint-web-assets/tokens/tokens';
import { XMark } from '@box/blueprint-web-assets/icons/Fill';
import messages from '../common/messages';

const IconInProgress = () => {
const { formatMessage } = useIntl();

return (
<div className="bcu-IconInProgress">
<XMark color={IconCtaIconHover} height={Size5} width={Size5} />
<LoadingIndicator aria-label={formatMessage(messages.loading)} className="bcu-IconInProgress-loading" />
</div>
);
};

export default IconInProgress;
23 changes: 10 additions & 13 deletions src/elements/content-uploader/ItemAction.scss
Original file line number Diff line number Diff line change
@@ -1,36 +1,33 @@
.bcu-item-action {
.crawler {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
display: flex;
align-items: center;
justify-content: center;

.bcu-ItemAction-loading,
.bcu-IconInProgress-loading {
position: relative; // Override default Blueprint position: `absolute`
}

button {
display: flex;

// Vertically center icon
svg {
display: block;
}

.be-icon-in-progress {
width: 24px;
height: 24px;

.bcu-IconInProgress {
// Hide cross icon without hover
svg {
display: none;
}
}

// Display cross icon on hover and hide loading indicator
&:hover .be-icon-in-progress {
&:hover .bcu-IconInProgress {
svg {
display: block;
}

.crawler {
.bcu-IconInProgress-loading {
display: none;
}
}
Expand Down
76 changes: 35 additions & 41 deletions src/elements/content-uploader/ItemAction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@ import * as React from 'react';
import { useIntl } from 'react-intl';
import { AxiosError } from 'axios';
import { Button, IconButton, LoadingIndicator, Tooltip } from '@box/blueprint-web';
import { ArrowCurveForward, Checkmark } from '@box/blueprint-web-assets/icons/Line';
import { EllipsisBadge, XMark } from '@box/blueprint-web-assets/icons/Fill';
import { ArrowCurveForward, Checkmark, XMark } from '@box/blueprint-web-assets/icons/Fill';
import { Size5, SurfaceStatusSurfaceSuccess } from '@box/blueprint-web-assets/tokens/tokens';
import IconInProgress from './IconInProgress';

import {
ERROR_CODE_UPLOAD_FILE_SIZE_LIMIT_EXCEEDED,
STATUS_PENDING,
STATUS_IN_PROGRESS,
STATUS_STAGED,
STATUS_COMPLETE,
STATUS_ERROR,
STATUS_IN_PROGRESS,
STATUS_PENDING,
STATUS_STAGED,
} from '../../constants';

import messages from '../common/messages';
Expand All @@ -22,37 +22,14 @@ import type { UploadStatus } from '../../common/types/upload';
import './ItemAction.scss';

export interface ItemActionProps {
error?: AxiosError;
error?: Partial<AxiosError>;
isFolder?: boolean;
isResumableUploadsEnabled: boolean;
onClick: React.MouseEventHandler<HTMLButtonElement>;
onUpgradeCTAClick?: () => void;
status: UploadStatus;
}

const getIconWithTooltip = (
icon: React.ReactNode,
isDisabled: boolean,
isLoading: boolean,
onClick: React.MouseEventHandler<HTMLButtonElement>,
tooltip: boolean,
tooltipText: string,
) => {
if (isLoading) {
return <LoadingIndicator aria-label="loading" />;
}

if (tooltip) {
return (
<Tooltip content={tooltipText}>
<IconButton aria-label={tooltipText} disabled={isDisabled} onClick={onClick} icon={() => icon} />
</Tooltip>
);
}

return <>{icon}</>;
};

const ItemAction = ({
error,
isFolder = false,
Expand All @@ -61,41 +38,51 @@ const ItemAction = ({
onUpgradeCTAClick,
status,
}: ItemActionProps) => {
const intl = useIntl();
let icon: React.ReactNode = <XMark color="black" height={Size5} width={Size5} />;
let tooltip;
let isLoading = false;
const { formatMessage } = useIntl();
const { code } = error || {};
const { formatMessage } = intl;

const LoadingIndicatorIcon = () => (
<LoadingIndicator aria-label={formatMessage(messages.loading)} className="bcu-ItemAction-loading" />
);

let Icon = XMark;
let tooltip;

if (isFolder && status !== STATUS_PENDING) {
return null;
}

switch (status) {
case STATUS_COMPLETE:
icon = <Checkmark aria-label="complete" color={SurfaceStatusSurfaceSuccess} height={Size5} width={Size5} />;
Icon = () => (
<Checkmark
aria-label={formatMessage(messages.complete)}
color={SurfaceStatusSurfaceSuccess}
height={Size5}
width={Size5}
/>
);
if (!isResumableUploadsEnabled) {
tooltip = messages.remove;
}
break;
case STATUS_ERROR:
icon = <ArrowCurveForward aria-label="error" color="black" height={Size5} width={Size5} />;
Icon = ArrowCurveForward;
tooltip = isResumableUploadsEnabled ? messages.resume : messages.retry;
break;
case STATUS_IN_PROGRESS:
case STATUS_STAGED:
if (isResumableUploadsEnabled) {
isLoading = true;
Icon = LoadingIndicatorIcon;
} else {
icon = <EllipsisBadge aria-label="staged" color="black" height={Size5} width={Size5} />;
Icon = IconInProgress;
tooltip = messages.uploadsCancelButtonTooltip;
}
break;
case STATUS_PENDING:
default:
if (isResumableUploadsEnabled) {
isLoading = true;
Icon = LoadingIndicatorIcon;
} else {
tooltip = messages.uploadsCancelButtonTooltip;
}
Expand All @@ -109,16 +96,23 @@ const ItemAction = ({
data-resin-target="large_version_error_inline_upgrade_cta"
variant="primary"
>
{intl.formatMessage(messages.uploadsFileSizeLimitExceededUpgradeMessageForUpgradeCta)}
{formatMessage(messages.uploadsFileSizeLimitExceededUpgradeMessageForUpgradeCta)}
</Button>
);
}

const isDisabled = status === STATUS_STAGED;
const tooltipText = tooltip && formatMessage(tooltip);

return (
<div className="bcu-item-action">
{getIconWithTooltip(icon, isDisabled, isLoading, onClick, tooltip, tooltipText)}
{tooltip ? (
<Tooltip content={tooltipText}>
<IconButton aria-label={tooltipText} disabled={isDisabled} icon={Icon} onClick={onClick} />
</Tooltip>
) : (
<Icon />
)}
</div>
);
};
Expand Down
7 changes: 4 additions & 3 deletions src/elements/content-uploader/ItemList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import type { UploadItem } from '../../common/types/upload';
import '@box/react-virtualized/styles.css';
import './ItemList.scss';

const ACTION_CELL_WIDTH = 32;

export interface ItemListProps {
isResumableUploadsEnabled?: boolean;
items: UploadItem[];
Expand All @@ -38,7 +40,6 @@ const ItemList = ({
const progressCell = progressCellRenderer(!!onUpgradeCTAClick);
const actionCell = actionCellRenderer(isResumableUploadsEnabled, onClick, onUpgradeCTAClick);
const removeCell = removeCellRenderer(onRemoveClick);
const baseIconWidth = 32;

return (
<Table
Expand Down Expand Up @@ -66,15 +67,15 @@ const ItemList = ({
cellRenderer={actionCell}
dataKey="status"
flexShrink={0}
width={onUpgradeCTAClick ? 100 : baseIconWidth}
width={onUpgradeCTAClick ? 100 : ACTION_CELL_WIDTH}
/>
{isResumableUploadsEnabled && (
<Column
className="bcu-item-list-action-column"
cellRenderer={removeCell}
dataKey="remove"
flexShrink={0}
width={baseIconWidth}
width={ACTION_CELL_WIDTH}
/>
)}
</Table>
Expand Down
21 changes: 0 additions & 21 deletions src/elements/content-uploader/ItemProgress.js

This file was deleted.

4 changes: 2 additions & 2 deletions src/elements/content-uploader/ItemProgress.scss
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
.bcu-item-progress {
.bcu-ItemProgress {
display: flex;
align-items: center;
}

.bcu-progress-label {
.bcu-ItemProgress-label {
min-width: 35px; // 100% takes up 34.27px
}
16 changes: 16 additions & 0 deletions src/elements/content-uploader/ItemProgress.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import * as React from 'react';
import ProgressBar from './ProgressBar';
import './ItemProgress.scss';

export interface ItemProgressProps {
progress: number;
}

const ItemProgress = ({ progress }: ItemProgressProps) => (
<div className="bcu-ItemProgress">
<ProgressBar percent={progress} />
<div className="bcu-ItemProgress-label">{progress}%</div>
</div>
);

export default ItemProgress;
16 changes: 5 additions & 11 deletions src/elements/content-uploader/ItemRemove.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import * as React from 'react';
import { useIntl } from 'react-intl';
import { IconButton, Tooltip } from '@box/blueprint-web';
import { GrayBlack, Size5 } from '@box/blueprint-web-assets/tokens/tokens';
import { XMark } from '@box/blueprint-web-assets/icons/Fill';

import type { UploadItem, UploadStatus } from '../../common/types/upload';
Expand All @@ -16,6 +15,8 @@ export interface ItemRemoveProps {
}

const ItemRemove = ({ onClick, status }: ItemRemoveProps) => {
const { formatMessage } = useIntl();

const resin: Record<string, string> = {};
let target = null;

Expand All @@ -29,20 +30,13 @@ const ItemRemove = ({ onClick, status }: ItemRemoveProps) => {
resin['data-resin-target'] = target;
}

const intl = useIntl();
const isDisabled = status === STATUS_STAGED;
const tooltipText = intl.formatMessage(messages.remove);
const tooltipText = formatMessage(messages.remove);

return (
<div className="bcu-item-action">
<Tooltip content={tooltipText} variant="standard">
<IconButton
aria-label={tooltipText}
disabled={isDisabled}
onClick={onClick}
icon={() => <XMark color={GrayBlack} height={Size5} width={Size5} />}
{...resin}
/>
<Tooltip content={tooltipText}>
<IconButton aria-label={tooltipText} disabled={isDisabled} onClick={onClick} icon={XMark} {...resin} />
</Tooltip>
</div>
);
Expand Down
8 changes: 4 additions & 4 deletions src/elements/content-uploader/ProgressBar.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import * as React from 'react';
import './ProgressBar.scss';

type Props = {
export interface ProgressBarProps {
percent?: number;
};
}

const ProgressBar = ({ percent }: Props) => {
const clampedPercentage = Math.max(0, Math.min(100, percent || 0));
const ProgressBar = ({ percent = 0 }: ProgressBarProps) => {
const clampedPercentage = Math.max(0, Math.min(100, percent));

const containerStyle = {
transitionDelay: clampedPercentage > 0 && clampedPercentage < 100 ? '0' : '0.4s',
Expand Down
Loading

0 comments on commit ba299b1

Please sign in to comment.