Skip to content

Commit

Permalink
NEW-GUI pipelines and projects pages - project and pipeline cards (#3780
Browse files Browse the repository at this point in the history
  • Loading branch information
AleksandrGorodetskii committed Dec 9, 2024
1 parent 9294e4b commit 0fcbce9
Show file tree
Hide file tree
Showing 8 changed files with 204 additions and 85 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { RunStatuses } from '@cloud-pipeline/core';
import type { CommonProps } from '../common.types';
import classNames from 'classnames';

type StatusIconProps = CommonProps & {
status: RunStatuses;
radius?: number;
strokeWidth?: number;
};

const statusClassNames: Record<RunStatuses, string> = {
[RunStatuses.success]: 'fill-green-600 stroke-green-600',
[RunStatuses.running]: 'fill-transparent stroke-green-600',
[RunStatuses.failure]: 'fill-red-600 stroke-red-600',
[RunStatuses.stopped]: 'fill-transparent stroke-red-600',
[RunStatuses.resuming]: 'fill-sky-600 stroke-sky-600',
[RunStatuses.paused]: 'fill-slate-400 stroke-slate-400',
[RunStatuses.pausing]: 'fill-sky-600 stroke-sky-600',
};

export function StatusIcon({
radius = 5,
strokeWidth = 3,
className,
style,
status,
}: StatusIconProps) {
return (
<svg
className={classNames(
className,
statusClassNames[status],
'rounded-full',
)}
style={style}
height={radius * 2}
width={radius * 2}>
<circle cx={radius} cy={radius} r={radius} strokeWidth={strokeWidth} />
</svg>
);
}
3 changes: 2 additions & 1 deletion portals-ui/packages/components/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import List, { ListHeader } from './components/list';
import type { UserCardProps } from './components/user-card';
import { UserCard } from './components/user-card';
import { StatusIcon } from './components/status-icon';
import '@epam/uui-components/styles.css';
import '@epam/uui/styles.css';
import './style.css';

export { List, UserCard, ListHeader };
export { List, UserCard, ListHeader, StatusIcon };
export type { UserCardProps };
export type * from './components/common.types';
export type * from './components/list/types';
15 changes: 15 additions & 0 deletions portals-ui/packages/core/src/utilities/dates.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc';

dayjs.extend(utc);

const displayFormat = 'YYYY-MM-DD, HH:mm:ss';

const displayDate = (date: string, format: string = displayFormat): string => {
if (!date) {
return '';
}
return dayjs.utc(date).local().format(format);
};

export { displayDate };
1 change: 1 addition & 0 deletions portals-ui/packages/core/src/utilities/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './acl';
export * from './misc';
export * from './users';
export * from './dates';
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Tag, Badge, FlexRow, RichTextView } from '@epam/uui';
import { Tag, Badge, FlexRow, Button, RichTextView } from '@epam/uui';
import ContentPersonFillIcon from '@epam/assets/icons/content-person-fill.svg?react';
import cn from 'classnames';
import { Link } from 'react-router-dom';
Expand Down Expand Up @@ -89,46 +89,54 @@ export const PipelineCard = ({

const filteredTag = useMemo(() => tags.filter(filterTag), [tags]);
return (
<div className={cn('ngs-container', className)} style={style}>
{/* {tags?.length && (
<div className="flex flex-wrap gap-1">
{tags.map((tag) => (
<Tag caption={tag} size="18" />
))}
</div>
)} */}
{filteredTag.length > 0 && (
<div className="flex flex-wrap gap-1">
{filteredTag.map((tag) => (
<NgsTag
key={tag.key}
tag={tag.key}
value={tag.value}
size="18"
className="shrink-0"
/>
))}
</div>
<div
className={cn(
mode === 'standard' ? 'ngs-container' : 'ngs-container-extended',
className,
)}

<FlexRow columnGap="12" size="24" alignItems="center">
<Link
className="text-[var(--uui-link)] hover:text-[var(--uui-link-hover)] no-underline"
to={`/pipeline/${id}`}>
<HighlightedText search={highlightedText}>{name}</HighlightedText>
</Link>

<Badge
icon={ContentPersonFillIcon}
caption={<NgsUserCard userName={owner} showTooltip={false} />}
color="neutral"
size="18"
cx="shrink-0"
/>
</FlexRow>

{description && (
<RichTextView cx="leading-4 text-sm">{description}</RichTextView>
style={style}>
<div className="flex flex-col">
{filteredTag.length > 0 && (
<div className="flex flex-wrap gap-1">
{filteredTag.map((tag) => (
<NgsTag
key={tag.key}
tag={tag.key}
value={tag.value}
size="18"
className="shrink-0"
/>
))}
</div>
)}
<FlexRow columnGap="12" size="24" alignItems="center">
<Link
className="text-[var(--uui-link)] hover:text-[var(--uui-link-hover)] no-underline"
to={`/pipeline/${id}`}>
<HighlightedText search={highlightedText}>{name}</HighlightedText>
</Link>
<Badge
icon={ContentPersonFillIcon}
caption={<NgsUserCard userName={owner} showTooltip={false} />}
color="neutral"
size="18"
cx="shrink-0"
/>
</FlexRow>
{description && (
<RichTextView cx="leading-4 text-sm">{description}</RichTextView>
)}
</div>
{mode === 'extended' && (
<div className="ml-auto flex items-center">
<Button
caption="Add to project"
fill="none"
color="secondary"
size="24"
onClick={() => null}
/>
</div>
)}
</div>
);
Expand Down
133 changes: 91 additions & 42 deletions portals-ui/sites/ngs-portal/src/pages/home/components/project-card.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import { Badge, FlexRow, RichTextView } from '@epam/uui';
import ContentPersonFillIcon from '@epam/assets/icons/content-person-fill.svg?react';
import ActionCalendarFillIcon from '@epam/assets/icons/action-calendar-fill.svg?react';
import cn from 'classnames';
import { Link } from 'react-router-dom';
import type { Project } from '@cloud-pipeline/core';
import { RunStatuses } from '@cloud-pipeline/core';
import {
displayDate,
executeAllowed,
readAllowed,
writeAllowed,
} from '@cloud-pipeline/core';
import type { CommonProps } from '@cloud-pipeline/components';
import { StatusIcon, type CommonProps } from '@cloud-pipeline/components';
import HighlightedText from '../../../shared/highlight-text';
import { NgsUserCard } from '../../../widgets/ngs-user-card';
import { useMemo } from 'react';
Expand Down Expand Up @@ -101,52 +104,98 @@ export const ProjectCard = ({

const hasSomeRights = read || write || execute;

const { showPermissionTags, showExtraInfo, showDescription, showStatusInfo } =
useMemo(
() => ({
showPermissionTags: mode === 'standard' && hasSomeRights,
showExtraInfo: mode === 'extended',
showDescription: !!description,
showStatusInfo: mode === 'extended',
}),
[description, hasSomeRights, mode],
);

return (
<div className={cn('ngs-container', className)} style={style}>
{filteredTag.length > 0 && (
<div className="flex flex-wrap gap-1">
{filteredTag.map((tag) => (
<NgsTag
key={tag.key}
tag={tag.key}
value={tag.value}
size="18"
className="shrink-0"
/>
))}
</div>
<div
className={cn(
mode === 'standard' ? 'ngs-container' : 'ngs-container-extended',
className,
)}

<FlexRow columnGap="12" size="24" alignItems="center">
<Link
className="text-[var(--uui-link)] hover:text-[var(--uui-link-hover)] no-underline"
to={`/project/${id}`}>
<HighlightedText search={highlightedText}>{name}</HighlightedText>
</Link>
<Badge
icon={ContentPersonFillIcon}
caption={<NgsUserCard userName={owner} showTooltip={false} />}
color="neutral"
size="18"
cx="shrink-0"
/>
</FlexRow>

{hasSomeRights && (
<FlexRow columnGap="6" size="24">
{read && (
<Badge size="18" fill="outline" caption="Read" color="info" />
)}
{write && (
<Badge size="18" fill="outline" caption="Write" color="warning" />
)}
{execute && (
<Badge size="18" fill="outline" caption="Execute" color="success" />
style={style}>
<div className="flex flex-col">
{filteredTag.length > 0 && (
<div className="flex flex-wrap gap-1">
{filteredTag.map((tag) => (
<NgsTag
key={tag.key}
tag={tag.key}
value={tag.value}
size="18"
className="shrink-0"
/>
))}
</div>
)}
<FlexRow columnGap="12" size="24" alignItems="center">
<Link
className="text-[var(--uui-link)] hover:text-[var(--uui-link-hover)] no-underline"
to={`/project/${id}`}>
<HighlightedText search={highlightedText}>{name}</HighlightedText>
</Link>
<Badge
icon={ContentPersonFillIcon}
caption={<NgsUserCard userName={owner} showTooltip={false} />}
color="neutral"
size="18"
cx="shrink-0"
/>
{showExtraInfo && (
<div className="text text-xs flex flex-nowrap gap-3">
<div className="flex flex-nowrap items-center gap-1">
<ActionCalendarFillIcon className="h-3 w-3 fill-current" />
{displayDate(project.createdDate)}
</div>
<div className="flex flex-nowrap items-center gap-1">
<ContentPersonFillIcon className="h-3 w-3 fill-current" />
{Math.floor(Math.random() * 10 + 1)} users
</div>
</div>
)}
</FlexRow>
{showPermissionTags && (
<FlexRow columnGap="6" size="24">
{read && (
<Badge size="18" fill="outline" caption="Read" color="info" />
)}
{write && (
<Badge size="18" fill="outline" caption="Write" color="warning" />
)}
{execute && (
<Badge
size="18"
fill="outline"
caption="Execute"
color="success"
/>
)}
</FlexRow>
)}
{showDescription && <RichTextView>{description}</RichTextView>}
</div>
{showStatusInfo && (
<div className="text text-sm ml-auto mt-0">
<div className="flex flex-nowrap items-baseline gap-2">
<StatusIcon status={RunStatuses.success} className="shrink-0" />
{Math.floor(Math.random() * 10 + 1)} running
</div>
<div className="flex flex-nowrap gap-2 max-w-80 items-baseline">
<StatusIcon status={RunStatuses.resuming} className="shrink-0" />
<span className="whitespace-break-spaces">
Last finished: RNA Sequence pipeline with a long name (version: 3)
</span>
</div>
</div>
)}

{description && <RichTextView>{description}</RichTextView>}
</div>
);
};
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
.ngs-container {
@apply px-3 py-2 bg-white space-y-1;
@apply px-3 py-2 bg-white space-y-1;
}

.ngs-container-extended {
@apply px-3 py-2 bg-white flex gap-2 flex-nowrap;
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export function ProjectsPage() {
//todo: search refactoring needed (see <ItemsPanel /> search)
return (
<ProjectsList
projects={projects}
projects={filteredProjects}
mode="extended"
filters={
<ProjectFilters
Expand Down

0 comments on commit 0fcbce9

Please sign in to comment.