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 { PropertyInfoTooltip, Tooltip } from '@nx/graph/ui-tooltips';
|
||||||
import { twMerge } from 'tailwind-merge';
|
import { twMerge } from 'tailwind-merge';
|
||||||
import { TagList } from '../tag-list/tag-list';
|
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 { TargetConfigurationGroupList } from '../target-configuration-details-group-list/target-configuration-details-group-list';
|
||||||
import { TooltipTriggerText } from '../target-configuration-details/tooltip-trigger-text';
|
import { TooltipTriggerText } from '../target-configuration-details/tooltip-trigger-text';
|
||||||
import { TargetTechnologies } from '../target-technologies/target-technologies';
|
import { TargetTechnologies } from '../target-technologies/target-technologies';
|
||||||
@ -105,6 +106,13 @@ export const ProjectDetails = ({
|
|||||||
{projectData.metadata?.description}
|
{projectData.metadata?.description}
|
||||||
</p>
|
</p>
|
||||||
) : null}
|
) : 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 ? (
|
{projectData.tags && projectData.tags.length ? (
|
||||||
<TagList className="mb-2" tags={projectData.tags} />
|
<TagList className="mb-2" tags={projectData.tags} />
|
||||||
) : null}
|
) : null}
|
||||||
|
|||||||
@ -122,6 +122,20 @@ export interface ProjectMetadata {
|
|||||||
description?: string;
|
description?: string;
|
||||||
technologies?: string[];
|
technologies?: string[];
|
||||||
targetGroups?: Record<string, string[]>;
|
targetGroups?: Record<string, string[]>;
|
||||||
|
owners?: {
|
||||||
|
[ownerId: string]: {
|
||||||
|
ownedFiles: {
|
||||||
|
files: ['*'] | string[];
|
||||||
|
fromConfig?: {
|
||||||
|
filePath: string;
|
||||||
|
location: {
|
||||||
|
startLine: number;
|
||||||
|
endLine: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TargetMetadata {
|
export interface TargetMetadata {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user