Skip to content
This repository has been archived by the owner on Jan 19, 2025. It is now read-only.

Commit

Permalink
feat(gui): usage based filters (#538)
Browse files Browse the repository at this point in the history
* feat(gui): parse filters for usages/usefulness

* feat(gui): update filter help text

* feat(gui): pass usage data around

* feat(gui): implement usage filter

* feat(gui): implement usefulness filter

* style: apply automatic fixes of linters

* fix: build errors

* fix: linter errors

* style: apply automatic fixes of linters

Co-authored-by: lars-reimann <lars-reimann@users.noreply.github.com>
  • Loading branch information
lars-reimann and lars-reimann authored Jun 4, 2022
1 parent 3dc3ebd commit 9880366
Show file tree
Hide file tree
Showing 26 changed files with 581 additions and 198 deletions.
4 changes: 2 additions & 2 deletions api-editor/gui/src/app/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ const App: React.FC = function () {

const [filter, setFilter] = useState('is:public');
const pythonFilter = createFilterFromString(filter);
const filteredPythonPackage = pythonFilter.applyToPackage(pythonPackage, useAppSelector(selectAnnotations));
const filteredPythonPackage = pythonFilter.applyToPackage(pythonPackage, useAppSelector(selectAnnotations), usages);

const userActionTarget = pythonPackage.getByRelativePathAsString(currentUserAction.target);

Expand Down Expand Up @@ -169,7 +169,7 @@ const App: React.FC = function () {
{currentUserAction.type === 'rename' && <RenameForm target={userActionTarget || pythonPackage} />}
</GridItem>
<GridItem gridArea="rightPane" overflow="auto">
<SelectionView pythonPackage={pythonPackage} pythonFilter={pythonFilter} />
<SelectionView pythonPackage={pythonPackage} pythonFilter={pythonFilter} usages={usages} />
</GridItem>

{showAnnotationImportDialog && <AnnotationImportDialog />}
Expand Down
112 changes: 112 additions & 0 deletions api-editor/gui/src/common/FilterHelpButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import {
Box,
Icon,
IconButton,
ListItem,
Popover,
PopoverArrow,
PopoverBody,
PopoverCloseButton,
PopoverContent,
PopoverHeader,
PopoverTrigger,
Text as ChakraText,
UnorderedList,
} from '@chakra-ui/react';
import React from 'react';

export const FilterHelpButton = function () {
return (
<Box>
<Popover>
<PopoverTrigger>
<IconButton variant="ghost" icon={<Icon name="help" />} aria-label="help" />
</PopoverTrigger>
<PopoverContent minWidth={462} fontSize="sm" marginRight={2}>
<PopoverArrow />
<PopoverCloseButton />
<PopoverHeader>Filter Options</PopoverHeader>
<PopoverBody>
<UnorderedList spacing={2}>
<ListItem>
<ChakraText>
<strong>is:[type]</strong>
</ChakraText>
<ChakraText>
Displays only elements that are of the given type. Replace [type] with one of{' '}
<em>module, class, function, parameter</em>.
</ChakraText>
</ListItem>
<ListItem>
<ChakraText>
<strong>is:[visibility]</strong>
</ChakraText>
<ChakraText>
Displays only elements that have the given visibility. Replace [visibility] with one
of <em>public, internal</em>.
</ChakraText>
</ListItem>
<ListItem>
<ChakraText>
<strong>name:xy</strong>
</ChakraText>
<ChakraText>
Displays only elements with names that contain the given string xy.
</ChakraText>
</ListItem>
<ListItem>
<ChakraText>
<strong>annotation:any</strong>
</ChakraText>
<ChakraText>Displays only elements that have been annotated.</ChakraText>
</ListItem>
<ListItem>
<ChakraText>
<strong>annotation:[type]</strong>
</ChakraText>
<ChakraText>
Displays only elements that are annotated with the given type xy. Replace [type]
with one of{' '}
<em>
@attribute, @boundary, @calledAfter, @constant, @enum, @group, @move, @optional,
@pure, @remove, @renaming, @required
</em>
.
</ChakraText>
</ListItem>
<ListItem>
<ChakraText>
<strong>usages:[operator][expected]</strong>
</ChakraText>
<ChakraText>
Displays only elements that are used a certain number of times. Replace [operator]
with one of <em>&lt;, &lt;=, &gt;=, &gt;</em> or omit it to match by equality.
Replace [expected] with the expected number of usages.
</ChakraText>
</ListItem>
<ListItem>
<ChakraText>
<strong>usefulness:[operator][expected]</strong>
</ChakraText>
<ChakraText>
Displays only elements that have a certain usefulness. Replace [operator] with one
of <em>&lt;, &lt;=, &gt;=, &gt;</em> or omit it to match by equality. Replace
[expected] with the expected usefulness.
</ChakraText>
</ListItem>
<ListItem>
<ChakraText>
<strong>!filter</strong>
</ChakraText>
<ChakraText>
Displays only elements that do not match the given filter. Possible filters are any
in this list.
</ChakraText>
</ListItem>
</UnorderedList>
</PopoverBody>
</PopoverContent>
</Popover>
</Box>
);
};
89 changes: 2 additions & 87 deletions api-editor/gui/src/common/MenuBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ import {
Heading,
HStack,
Icon,
IconButton,
Input,
ListItem,
Menu,
MenuButton,
MenuDivider,
Expand All @@ -22,16 +20,8 @@ import {
MenuItemOption,
MenuList,
MenuOptionGroup,
Popover,
PopoverArrow,
PopoverBody,
PopoverCloseButton,
PopoverContent,
PopoverHeader,
PopoverTrigger,
Spacer,
Text as ChakraText,
UnorderedList,
useColorMode,
VStack,
} from '@chakra-ui/react';
Expand All @@ -44,6 +34,7 @@ import PythonPackage from '../features/packageData/model/PythonPackage';
import { HeatMapMode, setHeatMapMode, togglePackageDataImportDialog } from '../features/packageData/packageDataSlice';
import { Setter } from './util/types';
import { toggleUsageImportDialog } from '../features/usages/usageSlice';
import { FilterHelpButton } from './FilterHelpButton';

interface MenuBarProps {
pythonPackage: PythonPackage;
Expand All @@ -52,82 +43,6 @@ interface MenuBarProps {
displayInferErrors: (errors: string[]) => void;
}

const HelpButton = function () {
return (
<Box>
<Popover>
<PopoverTrigger>
<IconButton variant="ghost" icon={<Icon name="help" />} aria-label="help" />
</PopoverTrigger>
<PopoverContent minWidth={462} fontSize="sm" marginRight={2}>
<PopoverArrow />
<PopoverCloseButton />
<PopoverHeader>Filter Options</PopoverHeader>
<PopoverBody>
<UnorderedList spacing={2}>
<ListItem>
<ChakraText>
<strong>is:[type]</strong>
</ChakraText>
<ChakraText>
Displays only elements that are of the given type. Replace [type] with one of{' '}
<em>module, class, function, parameter</em>.
</ChakraText>
</ListItem>
<ListItem>
<ChakraText>
<strong>is:[visibility]</strong>
</ChakraText>
<ChakraText>
Displays only elements that have the given visibility. Replace [visibility] with one
of <em>public, internal</em>.
</ChakraText>
</ListItem>
<ListItem>
<ChakraText>
<strong>name:xy</strong>
</ChakraText>
<ChakraText>
Displays only elements with names that contain the given string xy.
</ChakraText>
</ListItem>
<ListItem>
<ChakraText>
<strong>annotation:any</strong>
</ChakraText>
<ChakraText>Displays only elements that have been annotated.</ChakraText>
</ListItem>
<ListItem>
<ChakraText>
<strong>annotation:[type]</strong>
</ChakraText>
<ChakraText>
Displays only elements that are annotated with the given type xy. Replace [type]
with one of{' '}
<em>
@attribute, @boundary, @calledAfter, @constant, @enum, @group, @move, @optional,
@pure, @remove, @renaming, @required
</em>
.
</ChakraText>
</ListItem>
<ListItem>
<ChakraText>
<strong>!filter</strong>
</ChakraText>
<ChakraText>
Displays only elements that do not match the given filter. Possible filters are any
in this list.
</ChakraText>
</ListItem>
</UnorderedList>
</PopoverBody>
</PopoverContent>
</Popover>
</Box>
);
};

const DeleteAllAnnotations = function () {
const dispatch = useAppDispatch();
const [isOpen, setIsOpen] = useState(false);
Expand Down Expand Up @@ -310,7 +225,7 @@ const MenuBar: React.FC<MenuBarProps> = function ({ pythonPackage, filter, setFi
spellCheck={false}
minWidth="400px"
/>
<HelpButton />
<FilterHelpButton />
</HStack>
</Flex>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import PythonModule from '../PythonModule';
import PythonClass from '../PythonClass';
import PythonFunction from '../PythonFunction';
import NameFilter from './NameFilter';
import { initialState } from '../../../annotations/annotationSlice';
import { initialState as annotations } from '../../../annotations/annotationSlice';
import PythonDeclaration from '../PythonDeclaration';
import { UsageCountStore } from '../../../usages/model/UsageCountStore';

let pythonPackage: PythonPackage;

Expand Down Expand Up @@ -66,7 +67,7 @@ beforeEach(() => {
describe('AbstractPythonFilter::applyToPackage', () => {
test('keeps modules for which the filter returns true, their ancestors, and their descendants', () => {
const filter = new NameFilter('test_module_1');
const filteredPackage = filter.applyToPackage(pythonPackage, initialState);
const filteredPackage = filter.applyToPackage(pythonPackage, annotations, new UsageCountStore());

const modules = filteredPackage.modules;
expect(names(modules)).toEqual(['test_module_1']);
Expand All @@ -89,7 +90,7 @@ describe('AbstractPythonFilter::applyToPackage', () => {

test('keeps classes for which the filter returns true, their ancestors, and their descendants', () => {
const filter = new NameFilter('test_class_1');
const filteredPackage = filter.applyToPackage(pythonPackage, initialState);
const filteredPackage = filter.applyToPackage(pythonPackage, annotations, new UsageCountStore());

const modules = filteredPackage.modules;
expect(names(modules)).toEqual(['test_module_1']);
Expand All @@ -109,7 +110,7 @@ describe('AbstractPythonFilter::applyToPackage', () => {

test('keeps methods for which the filter returns true, their ancestors, and their descendants', () => {
const filter = new NameFilter('test_method_1');
const filteredPackage = filter.applyToPackage(pythonPackage, initialState);
const filteredPackage = filter.applyToPackage(pythonPackage, annotations, new UsageCountStore());

const modules = filteredPackage.modules;
expect(names(modules)).toEqual(['test_module_1']);
Expand All @@ -129,7 +130,7 @@ describe('AbstractPythonFilter::applyToPackage', () => {

test('keeps global functions for which the filter returns true, their ancestors, and their descendants', () => {
const filter = new NameFilter('test_global_function_1');
const filteredPackage = filter.applyToPackage(pythonPackage, initialState);
const filteredPackage = filter.applyToPackage(pythonPackage, annotations, new UsageCountStore());

const modules = filteredPackage.modules;
expect(names(modules)).toEqual(['test_module_1']);
Expand All @@ -146,7 +147,7 @@ describe('AbstractPythonFilter::applyToPackage', () => {

test('keeps parameters for which the filter returns true, their ancestors, and their descendants', () => {
const filter = new NameFilter('test_parameter_1');
const filteredPackage = filter.applyToPackage(pythonPackage, initialState);
const filteredPackage = filter.applyToPackage(pythonPackage, annotations, new UsageCountStore());

const modules = filteredPackage.modules;
expect(names(modules)).toEqual(['test_module_1']);
Expand All @@ -168,6 +169,6 @@ describe('AbstractPythonFilter::applyToPackage', () => {
});
});

function names(declarations: PythonDeclaration[]): string[] {
const names = function (declarations: PythonDeclaration[]): string[] {
return declarations.map((it) => it.name);
}
};
Loading

0 comments on commit 9880366

Please sign in to comment.