Skip to content
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ export interface BreadcrumbsProps extends HTMLAttributes<HTMLElement> {
* `onAction` for a plain link.
*/
onAction?: (id: Key) => void;
/**
* Maximum width in pixels for each crumb's label text. Labels longer than
* this truncate with an ellipsis. Omit to never truncate.
*/
maxItemWidth?: number;
}

const ELLIPSIS_ID = '__breadcrumbs_ellipsis__';
Expand Down Expand Up @@ -177,20 +182,22 @@ const Divider = ({
const CrumbLabel = ({
item,
size,
maxItemWidth,
}: {
item: BreadcrumbItemType;
size: BreadcrumbsSize;
maxItemWidth?: number;
}) => {
const Icon = item.icon;

return (
<span
className={cx(
'tw:flex tw:items-center tw:whitespace-nowrap',
sizes[size].gap
)}>
<span className={cx('tw:flex tw:min-w-0 tw:items-center', sizes[size].gap)}>
{Icon && <Icon className={cx('tw:shrink-0', sizes[size].icon)} />}
{item.label}
<span
className="tw:truncate"
style={maxItemWidth ? { maxWidth: maxItemWidth } : undefined}>
{item.label}
</span>
</span>
);
};
Expand Down Expand Up @@ -241,6 +248,7 @@ export const Breadcrumbs = ({
autoCollapse = false,
className,
onAction,
maxItemWidth,
'aria-label': ariaLabel = 'Breadcrumb',
...props
}: BreadcrumbsProps) => {
Expand Down Expand Up @@ -327,17 +335,25 @@ export const Breadcrumbs = ({
className={cx(linkClassName, styles[type].link, padding)}
href={onAction ? undefined : item.href}
onPress={() => onAction?.(item.id)}>
<CrumbLabel item={item} size={size} />
<CrumbLabel
item={item}
maxItemWidth={maxItemWidth}
size={size}
/>
</AriaLink>
) : (
<span
aria-current={isCurrent ? 'page' : undefined}
className={cx(
'tw:flex tw:items-center',
'tw:flex tw:min-w-0 tw:items-center',
padding,
isCurrent ? styles[type].current : 'tw:text-quaternary'
)}>
<CrumbLabel item={item} size={size} />
<CrumbLabel
item={item}
maxItemWidth={maxItemWidth}
size={size}
/>
</span>
)}
{!isCurrent && <Divider divider={divider} size={size} />}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,37 +44,43 @@ const getTabStyles = ({
}: AriaTabRenderProps) => ({
'button-brand': cx(
'tw:outline-focus-ring',
isSelected ? 'tw:font-semibold' : 'tw:font-medium',
isFocusVisible && 'tw:outline-2 tw:-outline-offset-2',
(isSelected || isHovered) &&
'tw:bg-brand-primary_alt tw:text-brand-secondary'
),
'button-gray': cx(
'tw:outline-focus-ring',
isSelected ? 'tw:font-semibold' : 'tw:font-medium',
isHovered && 'tw:bg-primary_hover tw:text-secondary',
isFocusVisible && 'tw:outline-2 tw:-outline-offset-2',
isSelected && 'tw:bg-active tw:text-secondary'
),
'button-border': cx(
'tw:outline-focus-ring',
isSelected ? 'tw:font-semibold' : 'tw:font-medium',
(isSelected || isHovered) &&
'tw:bg-primary_alt tw:text-secondary tw:shadow-sm',
isFocusVisible && 'tw:outline-2 tw:-outline-offset-2'
),
'button-minimal': cx(
'tw:rounded-lg tw:outline-focus-ring',
isSelected ? 'tw:font-semibold' : 'tw:font-medium',
isHovered && 'tw:text-secondary',
isFocusVisible && 'tw:outline-2 tw:-outline-offset-2',
isSelected &&
'tw:bg-primary_alt tw:text-secondary tw:shadow-xs tw:ring-1 tw:ring-primary tw:ring-inset'
),
underline: cx(
'tw:rounded-none tw:border-b-2 tw:border-transparent tw:outline-focus-ring',
isSelected ? 'tw:font-semibold' : 'tw:font-medium',
(isSelected || isHovered) &&
'tw:border-fg-brand-primary_alt tw:text-brand-secondary',
isFocusVisible && 'tw:outline-2 tw:-outline-offset-2'
),
line: cx(
'tw:rounded-none tw:border-l-2 tw:border-transparent tw:outline-focus-ring',
isSelected ? 'tw:font-semibold' : 'tw:font-medium',
(isSelected || isHovered) &&
'tw:border-fg-brand-primary_alt tw:text-brand-secondary',
isFocusVisible && 'tw:outline-2 tw:-outline-offset-2'
Expand All @@ -83,20 +89,20 @@ const getTabStyles = ({

const sizes = {
sm: {
'button-brand': 'tw:text-sm tw:font-semibold tw:py-2 tw:px-3',
'button-gray': 'tw:text-sm tw:font-semibold tw:py-2 tw:px-3',
'button-border': 'tw:text-sm tw:font-semibold tw:py-2 tw:px-3',
'button-minimal': 'tw:text-sm tw:font-semibold tw:py-2 tw:px-3',
underline: 'tw:text-sm tw:font-semibold tw:px-1 tw:pb-2.5 tw:pt-0',
line: 'tw:text-sm tw:font-semibold tw:pl-2.5 tw:pr-3 tw:py-0.5',
'button-brand': 'tw:text-sm tw:py-2 tw:px-3',
'button-gray': 'tw:text-sm tw:py-2 tw:px-3',
'button-border': 'tw:text-sm tw:py-2 tw:px-3',
'button-minimal': 'tw:text-sm tw:py-2 tw:px-3',
underline: 'tw:text-sm tw:px-1 tw:pb-2.5 tw:pt-0',
line: 'tw:text-sm tw:pl-2.5 tw:pr-3 tw:py-0.5',
},
md: {
'button-brand': 'tw:text-md tw:font-semibold tw:py-2.5 tw:px-3',
'button-gray': 'tw:text-md tw:font-semibold tw:py-2.5 tw:px-3',
'button-border': 'tw:text-md tw:font-semibold tw:py-2.5 tw:px-3',
'button-minimal': 'tw:text-md tw:font-semibold tw:py-2.5 tw:px-3',
underline: 'tw:text-md tw:font-semibold tw:px-1 tw:pb-2.5 tw:pt-0',
line: 'tw:text-md tw:font-semibold tw:pr-3.5 tw:pl-3 tw:py-1',
'button-brand': 'tw:text-md tw:py-2.5 tw:px-3',
'button-gray': 'tw:text-md tw:py-2.5 tw:px-3',
'button-border': 'tw:text-md tw:py-2.5 tw:px-3',
'button-minimal': 'tw:text-md tw:py-2.5 tw:px-3',
underline: 'tw:text-md tw:px-1 tw:pb-2.5 tw:pt-0',
line: 'tw:text-md tw:pr-3.5 tw:pl-3 tw:py-1',
},
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
*/

import {
Button,
Box,
ButtonUtility,
Card,
Dot,
Skeleton,
Typography,
} from '@openmetadata/ui-core-components';
Expand All @@ -28,7 +30,7 @@ import { getShortRelativeTime } from '../../../utils/date-time/DateTimeUtils';
import { ArchiveItem, ArchiveViewProps } from './ArchiveView.interface';

const ArchiveRowSkeleton: FC = () => (
<div className="tw:flex tw:items-center tw:gap-4 tw:px-4 tw:py-3 tw:border-b tw:border-secondary">
<div className="tw:flex tw:items-center tw:gap-4 tw:px-4 tw:py-3 tw:border-b tw:border-secondary tw:last:border-0">
<Skeleton
className="tw:shrink-0"
height="32px"
Expand Down Expand Up @@ -58,12 +60,15 @@ const ArchiveRow: FC<ArchiveRowProps> = ({ item, onDelete, onRestore }) => {
const Icon = item.type === 'article' ? File06 : FolderIcon;

return (
<div
className="tw:flex tw:items-center tw:gap-4 tw:px-4 tw:py-3 tw:border-b tw:border-secondary"
data-testid={`archive-row-${item.id}`}>
<div
<Box
align="center"
className="tw:px-4 tw:py-3 tw:border-b tw:border-secondary tw:last:border-0"
data-testid={`archive-row-${item.id}`}
gap={4}>
<Box
align="center"
className={classNames(
'tw:flex tw:h-8 tw:w-8 tw:shrink-0 tw:items-center tw:justify-center tw:rounded-lg',
'tw:h-8 tw:w-8 tw:shrink-0 tw:justify-center tw:rounded-lg',
item.type === 'article' ? 'tw:bg-brand-50' : 'tw:bg-purple-50'
)}>
<Icon
Expand All @@ -72,46 +77,48 @@ const ArchiveRow: FC<ArchiveRowProps> = ({ item, onDelete, onRestore }) => {
item.type === 'article' ? 'tw:text-brand-700' : 'tw:text-purple-500'
)}
/>
</div>
</Box>

<div className="tw:flex tw:min-w-0 tw:flex-1 tw:flex-col">
<Typography className="tw:truncate" size="text-sm" weight="medium">
<Box className="tw:min-w-0 tw:flex-1" direction="col">
<Typography ellipsis size="text-sm" weight="medium">
{item.name}
</Typography>
<Typography className="tw:text-gray-500" size="text-xs">
<Box align="center" gap={2}>
{item.updatedBy && (
<>
<Typography className="tw:text-quaternary" size="text-xs">
{t('label.archived-by', { name: item.updatedBy })}
{item.updatedAt && (
<>&nbsp;&middot;&nbsp;{getShortRelativeTime(item.updatedAt)}</>
)}
</Typography>
)}
{item.updatedAt && (
<>
<Dot className="tw:text-quaternary" size="micro" />
<Typography className="tw:text-quaternary" size="text-xs">
{getShortRelativeTime(item.updatedAt)}
</Typography>
</>
)}
{!item.updatedBy &&
item.updatedAt &&
getShortRelativeTime(item.updatedAt)}
</Typography>
</div>
</Box>
</Box>

<div className="tw:flex tw:items-center tw:gap-2 tw:shrink-0">
<Button
color="secondary"
<ButtonUtility
color="tertiary"
data-testid="restore-btn"
iconLeading={RefreshCcw01}
icon={<RefreshCcw01 size={20} />}
size="sm"
onPress={() => onRestore(item)}>
{t('label.restore')}
</Button>
<Button
color="secondary-destructive"
tooltip={t('label.restore')}
onClick={() => onRestore(item)}
/>
<ButtonUtility
color="tertiary"
data-testid="delete-btn"
iconLeading={Trash01}
icon={<Trash01 size={20} />}
size="sm"
onPress={() => onDelete(item)}>
{t('label.delete')}
</Button>
tooltip={t('label.delete')}
onClick={() => onDelete(item)}
/>
</div>
</div>
</Box>
);
};

Expand All @@ -123,7 +130,7 @@ const ArchiveView: FC<ArchiveViewProps> = ({
}) => {
if (isLoading) {
return (
<Card className="tw:flex tw:flex-col tw:overflow-hidden tw:h-[calc(100vh-378px)]">
<Card className="tw:flex tw:flex-col tw:overflow-hidden">
Comment thread
Rohit0301 marked this conversation as resolved.
Outdated
{Array.from({ length: 8 }).map((_, idx) => (
<ArchiveRowSkeleton key={idx} />
))}
Expand All @@ -140,9 +147,7 @@ const ArchiveView: FC<ArchiveViewProps> = ({
}

return (
<div
className="tw:flex tw:flex-1 tw:flex-col tw:overflow-y-auto tw:h-[calc(100vh-378px)]"
data-testid="archive-view">
<div data-testid="archive-view">
{data.map((item) => (
<ArchiveRow
item={item}
Expand Down
Loading
Loading