feat(graph): show owners in pdv (#28211)
<!-- Please make sure you have read the submission guidelines before posting an PR --> <!-- https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr --> <!-- Please make sure that your commit message follows our format --> <!-- Example: `fix(nx): must begin with lowercase` --> <!-- If this is a particularly complex change or feature addition, you can request a dedicated Nx release for this pull request branch. Mention someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they will confirm if the PR warrants its own release for testing purposes, and generate it for you if appropriate. --> ## Current Behavior <!-- This is the behavior we have today --> ## Expected Behavior <!-- This is the behavior we should expect with the changes in this PR --> <img width="428" alt="Screenshot 2024-09-30 at 8 54 38 PM" src="https://github.com/user-attachments/assets/59b47117-4136-4a59-8e08-c223eafa94b4"> <img width="445" alt="Screenshot 2024-09-30 at 8 53 49 PM" src="https://github.com/user-attachments/assets/9f9586fa-ae7a-44fe-bd67-305331b46bd4"> <img width="337" alt="Screenshot 2024-09-30 at 8 52 46 PM" src="https://github.com/user-attachments/assets/762a6aaa-7260-47db-87b4-b394b4da4df1"> ## Related Issue(s) <!-- Please link the issue being fixed so it gets closed when this is merged. --> Fixes #
This commit is contained in:
parent
c5bb723ed7
commit
1d10a19abc
@ -0,0 +1,42 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { OwnersList } from './owners-list';
|
||||
|
||||
const meta: Meta<typeof OwnersList> = {
|
||||
component: OwnersList,
|
||||
title: 'OwnersList',
|
||||
};
|
||||
export default meta;
|
||||
|
||||
type Story = StoryObj<typeof OwnersList>;
|
||||
|
||||
export const FewOwners: Story = {
|
||||
args: {
|
||||
owners: ['owner1', 'owner2', 'owner3'],
|
||||
},
|
||||
};
|
||||
export const ManyOwners: Story = {
|
||||
args: {
|
||||
owners: [
|
||||
'owner1',
|
||||
'owner2',
|
||||
'owner3',
|
||||
'owner4',
|
||||
'owner5',
|
||||
'owner6',
|
||||
'owner7',
|
||||
'owner8',
|
||||
'owner9',
|
||||
'owner10',
|
||||
'owner11',
|
||||
'owner12',
|
||||
'owner13',
|
||||
'owner14',
|
||||
'owner15',
|
||||
'owner16',
|
||||
'owner17',
|
||||
'owner18',
|
||||
'owner19',
|
||||
'owner20',
|
||||
],
|
||||
},
|
||||
};
|
||||
80
graph/ui-project-details/src/lib/owners-list/owners-list.tsx
Normal file
80
graph/ui-project-details/src/lib/owners-list/owners-list.tsx
Normal file
@ -0,0 +1,80 @@
|
||||
import { useState, useRef, useEffect } from 'react';
|
||||
import { Pill } from '../pill';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
|
||||
interface OwnersListProps {
|
||||
owners: string[];
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function OwnersList({ owners, className }: OwnersListProps) {
|
||||
const [isExpanded, _setIsExpanded] = useState(false);
|
||||
const [isOverflowing, setIsOverflowing] = useState(false);
|
||||
const ownersContainerRef = useRef<HTMLSpanElement>(null);
|
||||
|
||||
const checkOverflow = () => {
|
||||
requestAnimationFrame(() => {
|
||||
if (ownersContainerRef.current) {
|
||||
setIsOverflowing(
|
||||
ownersContainerRef.current.scrollWidth >
|
||||
ownersContainerRef.current.offsetWidth
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const setExpanded = (value: boolean) => {
|
||||
_setIsExpanded(value);
|
||||
checkOverflow();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
checkOverflow();
|
||||
|
||||
window.addEventListener('resize', checkOverflow);
|
||||
return () => window.removeEventListener('resize', checkOverflow);
|
||||
}, [ownersContainerRef]);
|
||||
|
||||
return (
|
||||
<div className={twMerge('relative max-w-full', className)}>
|
||||
<p className="flex min-w-0 font-medium leading-loose">
|
||||
<span className="inline-block">Owners:</span>
|
||||
|
||||
<span
|
||||
className={`inline-block ${
|
||||
isExpanded ? 'whitespace-normal' : 'whitespace-nowrap'
|
||||
} w-full max-w-full overflow-hidden transition-all duration-300`}
|
||||
style={{
|
||||
maskImage:
|
||||
isOverflowing && !isExpanded
|
||||
? 'linear-gradient(to right, black 80%, transparent 100%)'
|
||||
: 'none',
|
||||
}}
|
||||
ref={ownersContainerRef}
|
||||
>
|
||||
{owners.map((tag) => (
|
||||
<span key={tag} className="ml-2 font-mono lowercase">
|
||||
<Pill text={tag} />
|
||||
</span>
|
||||
))}
|
||||
{isExpanded && (
|
||||
<button
|
||||
onClick={() => setExpanded(false)}
|
||||
className="inline-block px-2 align-middle"
|
||||
>
|
||||
Show less
|
||||
</button>
|
||||
)}
|
||||
</span>
|
||||
{isOverflowing && !isExpanded && (
|
||||
<button
|
||||
onClick={() => setExpanded(true)}
|
||||
className="ml-1 inline-block whitespace-nowrap"
|
||||
>
|
||||
Show more
|
||||
</button>
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -8,6 +8,7 @@ import { EyeIcon } from '@heroicons/react/24/outline';
|
||||
import { PropertyInfoTooltip, Tooltip } from '@nx/graph/ui-tooltips';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
import { TagList } from '../tag-list/tag-list';
|
||||
import { OwnersList } from '../owners-list/owners-list';
|
||||
import { TargetConfigurationGroupList } from '../target-configuration-details-group-list/target-configuration-details-group-list';
|
||||
import { TooltipTriggerText } from '../target-configuration-details/tooltip-trigger-text';
|
||||
import { TargetTechnologies } from '../target-technologies/target-technologies';
|
||||
@ -105,6 +106,13 @@ export const ProjectDetails = ({
|
||||
{projectData.metadata?.description}
|
||||
</p>
|
||||
) : null}
|
||||
{projectData.metadata?.owners &&
|
||||
Object.keys(projectData.metadata?.owners).length ? (
|
||||
<OwnersList
|
||||
className="mb-2"
|
||||
owners={Object.keys(projectData.metadata?.owners)}
|
||||
/>
|
||||
) : null}
|
||||
{projectData.tags && projectData.tags.length ? (
|
||||
<TagList className="mb-2" tags={projectData.tags} />
|
||||
) : null}
|
||||
|
||||
@ -122,6 +122,20 @@ export interface ProjectMetadata {
|
||||
description?: string;
|
||||
technologies?: string[];
|
||||
targetGroups?: Record<string, string[]>;
|
||||
owners?: {
|
||||
[ownerId: string]: {
|
||||
ownedFiles: {
|
||||
files: ['*'] | string[];
|
||||
fromConfig?: {
|
||||
filePath: string;
|
||||
location: {
|
||||
startLine: number;
|
||||
endLine: number;
|
||||
};
|
||||
};
|
||||
}[];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export interface TargetMetadata {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user