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

Commit 477d835

Browse files
jofaulMasaralars-reimann
authored
feat: navigate to next / previous declaration (#511)
* small changes for arsam * treeview now expands when selecting new elements through next and prev buttons * style: Styling for the "next / previous declaration" buttons * Go to first/last element implemented * small bugfix * style: Styling for the "next / previous declaration" buttons * feat: when an element that isnt included in the current filter is selected, we now select the next/prev occurance of a filtered element. reworked code from ugly list to cool tree walk. removed go to first/last button texts but functionality is there * style: apply automatic fixes of linters * refactor: move previous/next buttons into SelectionView * refactor: use HStack instead of Box * style: apply automatic fixes of linters Co-authored-by: Arsam Islami <[email protected]> Co-authored-by: Lars Reimann <[email protected]> Co-authored-by: lars-reimann <[email protected]>
1 parent 4f8118d commit 477d835

File tree

3 files changed

+160
-23
lines changed

3 files changed

+160
-23
lines changed

api-editor/gui/src/app/App.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ const App: React.FC = function () {
169169
{currentUserAction.type === 'rename' && <RenameForm target={userActionTarget || pythonPackage} />}
170170
</GridItem>
171171
<GridItem gridArea="rightPane" overflow="auto">
172-
<SelectionView pythonPackage={pythonPackage} />
172+
<SelectionView pythonPackage={pythonPackage} pythonFilter={pythonFilter} />
173173
</GridItem>
174174

175175
{showAnnotationImportDialog && <AnnotationImportDialog />}

api-editor/gui/src/features/packageData/packageDataSlice.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ const packageDataSlice = createSlice({
3030
state.expandedInTreeView[action.payload] = true;
3131
}
3232
},
33+
expandParents(state, action: PayloadAction<string[]>) {
34+
const parents = action.payload;
35+
for (const parent of parents) {
36+
state.expandedInTreeView[parent] = true;
37+
}
38+
},
3339
setScrollOffset(state, action: PayloadAction<number>) {
3440
state.treeViewScrollOffset = action.payload;
3541
},
@@ -42,6 +48,7 @@ const packageDataSlice = createSlice({
4248
const { actions, reducer } = packageDataSlice;
4349
export const {
4450
toggleIsExpanded: toggleIsExpandedInTreeView,
51+
expandParents: expandParentsInTreeView,
4552
setScrollOffset: setTreeViewScrollOffset,
4653
toggleImportDialog: togglePackageDataImportDialog,
4754
} = actions;
Lines changed: 152 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { Box } from '@chakra-ui/react';
1+
import { Box, Button, HStack, Spacer, VStack } from '@chakra-ui/react';
22
import React from 'react';
3-
import { useLocation } from 'react-router';
3+
import { useLocation, useNavigate } from 'react-router';
44
import PythonClass from '../model/PythonClass';
55
import PythonFunction from '../model/PythonFunction';
66
import PythonModule from '../model/PythonModule';
@@ -10,34 +10,164 @@ import ClassView from './ClassView';
1010
import FunctionView from './FunctionView';
1111
import ModuleView from './ModuleView';
1212
import ParameterView from './ParameterView';
13+
import { expandParentsInTreeView } from '../packageDataSlice';
14+
import { useAppDispatch, useAppSelector } from '../../../app/hooks';
15+
import PythonDeclaration from '../model/PythonDeclaration';
16+
import AbstractPythonFilter from '../model/filters/AbstractPythonFilter';
17+
import { AnnotationsState, selectAnnotations } from '../../annotations/annotationSlice';
1318

1419
interface SelectionViewProps {
1520
pythonPackage: PythonPackage;
21+
pythonFilter: AbstractPythonFilter;
1622
}
1723

18-
const SelectionView: React.FC<SelectionViewProps> = function ({
19-
pythonPackage,
20-
}) {
21-
const declaration = pythonPackage.getByRelativePath(
22-
useLocation().pathname.split('/').splice(2),
23-
);
24+
const SelectionView: React.FC<SelectionViewProps> = function ({ pythonPackage, pythonFilter }) {
25+
const dispatch = useAppDispatch();
26+
const navigate = useNavigate();
27+
28+
const declaration = pythonPackage.getByRelativePath(useLocation().pathname.split('/').splice(2));
29+
const annotations = useAppSelector(selectAnnotations);
30+
31+
if (!declaration) {
32+
return <></>;
33+
}
2434

2535
return (
26-
<Box padding={4}>
27-
{declaration instanceof PythonFunction && (
28-
<FunctionView pythonFunction={declaration} />
29-
)}
30-
{declaration instanceof PythonClass && (
31-
<ClassView pythonClass={declaration} />
32-
)}
33-
{declaration instanceof PythonModule && (
34-
<ModuleView pythonModule={declaration} />
35-
)}
36-
{declaration instanceof PythonParameter && (
37-
<ParameterView pythonParameter={declaration} />
38-
)}
39-
</Box>
36+
<VStack h="100%">
37+
<Box w="100%" flexGrow={1} overflowY="scroll">
38+
<Box padding={4}>
39+
{declaration instanceof PythonFunction && <FunctionView pythonFunction={declaration} />}
40+
{declaration instanceof PythonClass && <ClassView pythonClass={declaration} />}
41+
{declaration instanceof PythonModule && <ModuleView pythonModule={declaration} />}
42+
{declaration instanceof PythonParameter && <ParameterView pythonParameter={declaration} />}
43+
</Box>
44+
</Box>
45+
46+
<Spacer />
47+
48+
<HStack borderTop={1} layerStyle="subtleBorder" padding="0.5em 1em" w="100%">
49+
<Button
50+
onClick={() => {
51+
let navStr = getPreviousElementPath(declaration, pythonFilter, annotations);
52+
if (navStr != null) {
53+
//navigate to element
54+
navigate(`/${navStr}`);
55+
56+
//update tree selection
57+
const parents = getParents(navStr, pythonPackage);
58+
dispatch(expandParentsInTreeView(parents));
59+
}
60+
}}
61+
>
62+
Previous
63+
</Button>
64+
<Button
65+
onClick={() => {
66+
let navStr = getNextElementPath(declaration, pythonFilter, annotations);
67+
if (navStr != null) {
68+
//navigate to element
69+
navigate(`/${navStr}`);
70+
71+
//update tree selection
72+
const parents = getParents(navStr, pythonPackage);
73+
dispatch(expandParentsInTreeView(parents));
74+
}
75+
}}
76+
>
77+
Next
78+
</Button>
79+
</HStack>
80+
</VStack>
4081
);
4182
};
4283

84+
const getNextElementPath = function (
85+
current: PythonDeclaration,
86+
filter: AbstractPythonFilter,
87+
annotations: AnnotationsState,
88+
): string | null {
89+
const nextElement = getNextElementInTree(current);
90+
if (nextElement != null) {
91+
if (filter.shouldKeepDeclaration(nextElement, annotations)) {
92+
return nextElement.pathAsString();
93+
}
94+
return getNextElementPath(nextElement, filter, annotations);
95+
}
96+
return null;
97+
};
98+
99+
const getNextElementInTree = function (current: PythonDeclaration): PythonDeclaration | null {
100+
if (current.children().length > 0) {
101+
return current.children()[0];
102+
} else if (current.parent() != null) {
103+
return getNextFromParentInTree(current);
104+
}
105+
return null;
106+
};
107+
108+
const getNextFromParentInTree = function (current: PythonDeclaration): PythonDeclaration | null {
109+
if (current instanceof PythonPackage && current.children().length > 0) {
110+
return current.children()[0];
111+
}
112+
const parent = current.parent();
113+
if (parent != null) {
114+
const index = parent.children().indexOf(current);
115+
if (parent.children().length > index + 1) {
116+
return parent.children()[index + 1];
117+
}
118+
return getNextFromParentInTree(parent);
119+
}
120+
return null;
121+
};
122+
123+
const getPreviousElementPath = function (
124+
current: PythonDeclaration,
125+
filter: AbstractPythonFilter,
126+
annotations: AnnotationsState,
127+
): string | null {
128+
const previousElement = getPreviousElementInTree(current);
129+
if (previousElement != null) {
130+
if (filter.shouldKeepDeclaration(previousElement, annotations)) {
131+
return previousElement.pathAsString();
132+
}
133+
return getPreviousElementPath(previousElement, filter, annotations);
134+
}
135+
return null;
136+
};
137+
138+
const getPreviousElementInTree = function (current: PythonDeclaration): PythonDeclaration | null {
139+
const parent = current.parent();
140+
if (parent != null) {
141+
const index = parent.children().indexOf(current);
142+
if (index > 0) {
143+
return getLastElementInTree(parent.children()[index - 1]);
144+
}
145+
if (parent instanceof PythonPackage) {
146+
return getLastElementInTree(parent);
147+
}
148+
return parent;
149+
}
150+
return null;
151+
};
152+
153+
const getLastElementInTree = function (current: PythonDeclaration): PythonDeclaration {
154+
if (current.children().length > 0) {
155+
return getLastElementInTree(current.children()[current.children().length - 1]);
156+
}
157+
return current;
158+
};
159+
160+
const getParents = function (navStr: string, filteredPythonPackage: PythonPackage): string[] {
161+
const parents: string[] = [];
162+
let currentElement = filteredPythonPackage.getByRelativePathAsString(navStr);
163+
if (currentElement != null) {
164+
currentElement = currentElement.parent();
165+
while (currentElement != null) {
166+
parents.push(currentElement.pathAsString());
167+
currentElement = currentElement.parent();
168+
}
169+
}
170+
return parents;
171+
};
172+
43173
export default SelectionView;

0 commit comments

Comments
 (0)