Skip to content

Commit

Permalink
Merge pull request #214 from opossum-tool/Finalize_context_menu_and_u…
Browse files Browse the repository at this point in the history
…pdate_docs

Finalize context menu and update docs
  • Loading branch information
nicarl authored Dec 1, 2021
2 parents 366172b + 3fdcfb2 commit a3a8827
Show file tree
Hide file tree
Showing 8 changed files with 140 additions and 18 deletions.
17 changes: 13 additions & 4 deletions USER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,14 @@ _File_ menu with the same name).

### Search

To search for a path, open the `Edit` menu and select `Search for Files and Folders`.
To search for a path, press `CTRL + F` or open the `Edit` menu and select `Search for Files and Folders`.

![integration](./docs/user_guide_screenshots/search.png)

### View Project Metadata

To view project metadata, open the `File` menu and select `Show Project Metadata`.

### Exporting Formats

It is possible to directly export data to files. The following formats are available:
Expand Down Expand Up @@ -219,6 +223,9 @@ The `Attribution Details Column`, if editable, shows the following buttons:
- _Delete_, deletes the attribution of the selected resource only.
- _Delete Globally_, (shown only if the attribution of the selected resource is also linked to other resources)
deletes the attribution for all the linked resources.
- _Mark for replacement_, allows to mark an attribution for replacement. After marking an attribution.
One can navigate to another attribution and press the _Replace marked_ button. This opens a popup. In the popup,
clicking the _Replace_ button removes the marked attribution and replaces it by the currently selected one.

The _SAVE_ / _SAVE GLOBALLY_ and _Undo_ buttons are disabled if no change has been made.

Expand All @@ -228,6 +235,11 @@ the respective attribution.
The `Attribution Details Column`, when a signal is selected, shows the _HIDE_ button. It can be used to hide the given
signal in the App for the current input/output files, and it will not have any consequence in the DB.

Instead of the buttons, the context menu can be used to execute all available actions out of _Delete_,
_Delete Globally_, _Confirm_, _Confirm Globally_, _Mark for replacement_, _Hide_ and _Show Resources_. To open the
context menu, right-click a signal or an attribution, e.g. in the `Attributions Sub-Panel`, `Signals Sub-Panel` or
`Attribution List`.

### Attribution View

![integration](./docs/user_guide_screenshots/attribution_view.png)
Expand All @@ -254,9 +266,6 @@ The `Selected Attribution Panel` looks much like the `Selected Resource Panel`.
the `Selected Resource Panel`. They are always editable.
- The _SAVE_ and _Delete_ buttons allow saving/deleting the selected attribution. Note that the changes affect multiple
resources if the selected attribution is linked to multiple resources.
- The _Mark for replacement_ button allows to mark an attribution for replacement. After marking an attribution.
One can navigate to another attribution and press the _Replace marked_ button. This opens a popup. In the popup,
clicking the _Replace_ button removes the marked attribution and replaces it by the currently selected one.
- A `Resource List` shows the path of all resources linked to the selected attribution. Clicking on a path shows the
selected resource in the `Audit View`.

Expand Down
22 changes: 20 additions & 2 deletions src/Frontend/Components/ContextMenu/ContextMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import makeStyles from '@mui/styles/makeStyles';
import { PopoverPosition, PopoverReference } from '@mui/material';
import { OpossumColors } from '../../shared-styles';
import OpenInBrowserIcon from '@mui/icons-material/OpenInBrowser';
import VisibilityOffIcon from '@mui/icons-material/VisibilityOff';
import VisibilityIcon from '@mui/icons-material/Visibility';

const useStyles = makeStyles({
icon: {
Expand All @@ -43,6 +45,8 @@ const BUTTON_TITLE_TO_ICON_MAP: {
[ButtonText.UnmarkForReplacement]: <CheckBoxIcon fontSize="small" />,
[ButtonText.ReplaceMarked]: <MergeTypeIcon fontSize="small" />,
[ButtonText.ShowResources]: <OpenInBrowserIcon fontSize="small" />,
[ButtonText.Hide]: <VisibilityOffIcon fontSize="small" />,
[ButtonText.Unhide]: <VisibilityIcon fontSize="small" />,
};

export interface ContextMenuItem {
Expand All @@ -58,6 +62,8 @@ interface ContextMenuProps {
menuItems: Array<ContextMenuItem>;
children: React.ReactNode;
activation: ContextMenuActivation;
onClose?(): void;
onOpen?(): void;
}

interface anchorAttributes {
Expand Down Expand Up @@ -102,11 +108,17 @@ export function ContextMenu(props: ContextMenuProps): ReactElement | null {
: { onClick: handleClick, onContextMenu: handleClick };

function handleClose(): void {
if (props.onClose) {
props.onClose();
}
setAnchorPosition(undefined);
setAnchorElement(null);
}

function handleClick(event: React.MouseEvent<HTMLElement>): void {
if (props.onOpen && displayedMenuItems.length > 0) {
props.onOpen();
}
setAnchorPosition({
left: event.clientX - 2,
top: event.clientY - 4,
Expand All @@ -118,9 +130,15 @@ export function ContextMenu(props: ContextMenuProps): ReactElement | null {
<>
<div
onClick={clickHandlers.onClick}
onContextMenu={clickHandlers.onContextMenu}
onContextMenu={(event): void => {
if (isContextMenuOpen) {
handleClose();
} else if (clickHandlers.onContextMenu) {
clickHandlers.onContextMenu(event);
}
}}
>
{props.children}
{props.children}{' '}
</div>
<MuiMenu
open={isContextMenuOpen}
Expand Down
25 changes: 25 additions & 0 deletions src/Frontend/Components/ContextMenu/__tests__/ContextMenu.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,29 @@ describe('The ContextMenu', () => {
fireEvent.click(screen.getByText(ButtonText.Save));
expect(onClickMock).toHaveBeenCalledTimes(1);
});

test('renders and calls onOpen and onClose correctly', () => {
const testElementText = 'Test Element';
const onCloseMock = jest.fn();
const onOpenMock = jest.fn();
render(
<ContextMenu
menuItems={testMenuItems}
activation={'both'}
onClose={onCloseMock}
onOpen={onOpenMock}
>
<p>{testElementText}</p>
</ContextMenu>
);

expectContextMenuIsNotShown();

fireEvent.contextMenu(screen.getByText(testElementText));
expectContextMenuIsShown();
expect(onOpenMock).toHaveBeenCalledTimes(1);

fireEvent.click(screen.getByText(ButtonText.Save));
expect(onCloseMock).toHaveBeenCalledTimes(1);
});
});
44 changes: 35 additions & 9 deletions src/Frontend/Components/ListCard/ListCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import { OpossumColors } from '../../shared-styles';
import { ListCardConfig } from '../../types/types';

const defaultCardHeight = 40;
const hoveredSelectedBackgroundColor = OpossumColors.middleBlueOnHover;
const hoveredBackgroundColor = OpossumColors.lightestBlueOnHover;
const defaultBackgroundColor = OpossumColors.lightestBlue;
const packageBorder = `1px ${OpossumColors.white} solid`;

const useStyles = makeStyles({
root: {
Expand All @@ -24,19 +28,26 @@ const useStyles = makeStyles({
cursor: 'pointer',
},
},
hoveredPackage: {
border: packageBorder,
background: hoveredBackgroundColor,
},
package: {
border: `1px ${OpossumColors.white} solid`,
background: OpossumColors.lightestBlue,
border: packageBorder,
background: defaultBackgroundColor,
'&:hover': {
background: OpossumColors.lightestBlueOnHover,
background: hoveredBackgroundColor,
},
},
externalAttribution: {
background: OpossumColors.lightestBlue,
background: defaultBackgroundColor,
'&:hover': {
background: OpossumColors.lightestBlueOnHover,
background: hoveredBackgroundColor,
},
},
hoveredExternalAttribution: {
background: hoveredBackgroundColor,
},
resource: {
background: OpossumColors.white,
'&:hover': {
Expand All @@ -47,9 +58,12 @@ const useStyles = makeStyles({
selected: {
background: OpossumColors.middleBlue,
'&:hover': {
background: OpossumColors.middleBlueOnHover,
background: hoveredSelectedBackgroundColor,
},
},
hoveredSelected: {
background: hoveredSelectedBackgroundColor,
},
markedForReplacement: {
borderRightWidth: 'medium',
borderRightColor: OpossumColors.brown,
Expand Down Expand Up @@ -155,10 +169,22 @@ export function ListCard(props: ListCardProps): ReactElement | null {
<div
className={clsx(
classes.root,
props.cardConfig.isResource ? classes.resource : classes.package,
props.cardConfig.isExternalAttribution && classes.externalAttribution,
props.cardConfig.isResource
? classes.resource
: props.cardConfig.isContextMenuOpen
? classes.hoveredPackage
: classes.package,
props.cardConfig.isExternalAttribution
? props.cardConfig.isContextMenuOpen
? classes.hoveredExternalAttribution
: classes.externalAttribution
: null,
props.cardConfig.isHeader ? classes.header : classes.hover,
props.cardConfig.isSelected && classes.selected,
props.cardConfig.isSelected
? props.cardConfig.isContextMenuOpen
? classes.hoveredSelected
: classes.selected
: null,
props.cardConfig.isMarkedForReplacement && classes.markedForReplacement,
props.cardConfig.isResolved && classes.resolved
)}
Expand Down
13 changes: 12 additions & 1 deletion src/Frontend/Components/PackageCard/PackageCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ export function PackageCard(props: PackageCardProps): ReactElement | null {
getAttributionIdMarkedForReplacement
);

const [isContextMenuOpen, setIsContextMenuOpen] = useState(false);
const [showAssociatedResourcesPopup, setShowAssociatedResourcesPopup] =
useState<boolean>(false);

Expand Down Expand Up @@ -310,6 +311,10 @@ export function PackageCard(props: PackageCardProps): ReactElement | null {
},
];

function toggleIsContextMenuOpen(): void {
setIsContextMenuOpen(!isContextMenuOpen);
}

return (
<>
{!Boolean(props.hideContextMenu) && (
Expand All @@ -323,13 +328,19 @@ export function PackageCard(props: PackageCardProps): ReactElement | null {
displayedAttributionName={getCardLabels(props.cardContent)[0] || ''}
/>
)}
<ContextMenu menuItems={contextMenuItems} activation={'onRightClick'}>
<ContextMenu
menuItems={contextMenuItems}
activation={'onRightClick'}
onClose={toggleIsContextMenuOpen}
onOpen={toggleIsContextMenuOpen}
>
<ListCard
text={packageLabels[0] || ''}
secondLineText={packageLabels[1] || undefined}
cardConfig={{
...props.cardConfig,
isMarkedForReplacement,
isContextMenuOpen,
}}
count={props.packageCount}
onClick={props.onClick}
Expand Down
30 changes: 30 additions & 0 deletions src/Frontend/test-helpers/context-menu-test-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ export function expectContextMenuIsNotShown(
cardLabel,
ButtonText.Delete
);
closeContextMenuOnCardPackageCard(screen, cardLabel);
}

export function expectNoConfirmationButtonsShown(
Expand Down Expand Up @@ -343,6 +344,7 @@ export function expectButtonNotInPackageContextMenu(
const buttonAttribute = button.attributes.getNamedItem('aria-disabled');

expect(buttonAttribute).toBeNull();
closeContextMenuOnCardPackageCard(screen, cardLabel);
}

function expectButtonInPackageContextMenuIsNotShown(
Expand All @@ -352,6 +354,7 @@ function expectButtonInPackageContextMenuIsNotShown(
): void {
openContextMenuOnCardPackageCard(screen, cardLabel);
expect(screen.queryByRole('button', { name: buttonLabel })).toBeFalsy();
closeContextMenuOnCardPackageCard(screen, cardLabel);
}

export function clickOnButtonInPackageContextMenu(
Expand All @@ -373,6 +376,13 @@ function openContextMenuOnCardPackageCard(
fireEvent.contextMenu(screen.getByText(cardLabel) as Element);
}

function closeContextMenuOnCardPackageCard(
screen: Screen,
cardLabel: string
): void {
fireEvent.contextMenu(screen.getByText(cardLabel) as Element);
}

export function expectCorrectButtonsInPackageInPackagePanelContextMenu(
screen: Screen,
packageName: string,
Expand Down Expand Up @@ -410,6 +420,11 @@ export function expectButtonInPackageInPackagePanelContextMenu(
const buttonAttribute = button.attributes.getNamedItem('aria-disabled');

expect(buttonAttribute).toBe(null);
closeContextMenuOnPackageInPackagePanel(
screen,
packageName,
packagePanelName
);
}

function expectButtonInPackageInPackagePanelContextMenuIsNotShown(
Expand All @@ -420,6 +435,11 @@ function expectButtonInPackageInPackagePanelContextMenuIsNotShown(
): void {
openContextMenuOnPackageInPackagePanel(screen, packageName, packagePanelName);
expect(screen.queryByRole('button', { name: buttonLabel })).toBeFalsy();
closeContextMenuOnPackageInPackagePanel(
screen,
packageName,
packagePanelName
);
}

export function clickOnButtonInPackageInPackagePanelContextMenu(
Expand All @@ -442,3 +462,13 @@ function openContextMenuOnPackageInPackagePanel(
// eslint-disable-next-line testing-library/prefer-screen-queries
fireEvent.contextMenu(getByText(packagesPanel, packageName));
}

function closeContextMenuOnPackageInPackagePanel(
screen: Screen,
packageName: string,
packagePanelName: string
): void {
const packagesPanel = getPackagePanel(screen, packagePanelName);
// eslint-disable-next-line testing-library/prefer-screen-queries
fireEvent.contextMenu(getByText(packagesPanel, packageName));
}
6 changes: 4 additions & 2 deletions src/Frontend/test-helpers/package-panel-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,10 @@ export function expectValueInAddToAttributionList(
(
(
(
(screen.getAllByLabelText(/add/)[0].parentElement as HTMLElement)
.parentElement as HTMLElement
(
(screen.getAllByLabelText(/add/)[0].parentElement as HTMLElement)
.parentElement as HTMLElement
).parentElement as HTMLElement
).parentElement as HTMLElement
).parentElement as HTMLElement
).parentElement as HTMLElement
Expand Down
1 change: 1 addition & 0 deletions src/Frontend/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export interface ListCardConfig {
firstParty?: boolean;
followUp?: boolean;
isHeader?: boolean;
isContextMenuOpen?: boolean;
}

export interface PathPredicate {
Expand Down

0 comments on commit a3a8827

Please sign in to comment.