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

Commit 5e98938

Browse files
nvollrothGideonKoeniglars-reimannGideonKoenigMasara
authored
feat: statistics View with bar and line charts (#644)
* feat: statistics View with bar and line charts end of day push * fix: issues after merge * style: fix lint error * style: apply automatic fixes of linters * refactor: move functions to UsageCountStore fix: made sure to count only public elements * update: merged with changes from main * style: apply automatic fixes of linters * update: styling of bar and line charts * style: apply automatic fixes of linters * update: styling of bar and line charts * style: apply automatic fixes of linters * test: Add test file for StatisticView.ts * test: Properly integrate prewritten tests feat: StatisticsView now displays two rows of Charts that properly stretch and wrap as proposed * refactor: proper integration of last merge * style: apply automatic fixes of linters * fix: test was checking for object equality instead of value equality * fix: test data for getParameterValues was missing an entry for usefull parameters * feat(gui): only have one way to trigger statistics view * refactor(gui): move data to component that uses it * refactor(gui): minor clean up * fix(gui): change URL of statistics view, so it can never clash with the name of a Python package * fix(gui): remove console.log * refactor(gui): shorten functions * refactor(gui): minor changes * style: apply automatic fixes of linters Co-authored-by: GideonKoenig <[email protected]> Co-authored-by: Lars Reimann <[email protected]> Co-authored-by: lars-reimann <[email protected]> Co-authored-by: GideonKoenig <[email protected]> Co-authored-by: Arsam Islami <[email protected]> Co-authored-by: GideonKoenig <[email protected]>
1 parent 9fe89f8 commit 5e98938

File tree

6 files changed

+568
-28
lines changed

6 files changed

+568
-28
lines changed

api-editor/gui/src/common/MenuBar.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ export const MenuBar: React.FC<MenuBarProps> = function ({ displayInferErrors })
6464
};
6565

6666
const setStatisticsViewPath = () => {
67-
navigate(`/statisticsView`);
67+
navigate(`/statistics-view`);
6868
};
6969

7070
const colorModeArray: string[] = [];
@@ -136,6 +136,8 @@ export const MenuBar: React.FC<MenuBarProps> = function ({ displayInferErrors })
136136
</Menu>
137137
</Box>
138138

139+
<Button onClick={setStatisticsViewPath}>Statistics View</Button>
140+
139141
<Box>
140142
<Menu closeOnSelect={false}>
141143
<MenuButton as={Button} rightIcon={<Icon as={FaChevronDown} />}>
@@ -148,10 +150,6 @@ export const MenuBar: React.FC<MenuBarProps> = function ({ displayInferErrors })
148150
</MenuItemOption>
149151
</MenuOptionGroup>
150152
<MenuDivider />
151-
<MenuItemOption value={'statistics'} onClick={setStatisticsViewPath}>
152-
Statistics
153-
</MenuItemOption>
154-
<MenuDivider />
155153
<MenuGroup title="Module/Class/Function Sorting">
156154
<MenuOptionGroup
157155
type="radio"

api-editor/gui/src/features/packageData/model/PythonPackage.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import { PythonDeclaration } from './PythonDeclaration';
22
import { PythonModule } from './PythonModule';
33
import { Optional } from '../../../common/util/types';
4+
import { PythonClass } from './PythonClass';
5+
import { PythonFunction } from './PythonFunction';
6+
import { PythonParameter } from './PythonParameter';
47

58
interface PythonPackageShallowCopy {
69
distribution?: string;
@@ -54,4 +57,51 @@ export class PythonPackage extends PythonDeclaration {
5457
toString(): string {
5558
return `Package "${this.distribution}/${this.name} v${this.version}"`;
5659
}
60+
61+
getModules(): PythonModule[] {
62+
return this.children();
63+
}
64+
65+
getClasses(): PythonClass[] {
66+
let result: PythonClass[] = [];
67+
for (const module of this.getModules()) {
68+
let children = module.children();
69+
for (const child of children) {
70+
if (child instanceof PythonClass) {
71+
result.push(child);
72+
}
73+
}
74+
}
75+
return result;
76+
}
77+
78+
getFunctions(): PythonFunction[] {
79+
let result: PythonFunction[] = [];
80+
for (const module of this.getModules()) {
81+
let children = module.children();
82+
for (const child of children) {
83+
if (child instanceof PythonFunction) {
84+
result.push(child);
85+
}
86+
}
87+
}
88+
for (const pythonClass of this.getClasses()) {
89+
let children = pythonClass.children();
90+
for (const child of children) {
91+
result.push(child);
92+
}
93+
}
94+
return result;
95+
}
96+
97+
getParameters(): PythonParameter[] {
98+
let result: PythonParameter[] = [];
99+
for (const pythonFunction of this.getFunctions()) {
100+
let children = pythonFunction.children();
101+
for (const child of children) {
102+
result.push(child);
103+
}
104+
}
105+
return result;
106+
}
57107
}
Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Box, VStack } from '@chakra-ui/react';
1+
import { Box } from '@chakra-ui/react';
22
import React from 'react';
33
import { useLocation } from 'react-router';
44
import { PythonClass } from '../model/PythonClass';
@@ -18,15 +18,11 @@ export const SelectionView: React.FC = function () {
1818
const declaration = rawPythonPackage.getDeclarationById(useLocation().pathname.split('/').splice(1).join('/'));
1919
const location = useLocation().pathname;
2020

21-
if (location === '/statisticsView') {
21+
if (location === '/statistics-view') {
2222
return (
23-
<VStack h="100%">
24-
<Box w="100%" flexGrow={1} overflowY="scroll">
25-
<Box padding={4}>
26-
<StatisticsView />
27-
</Box>
28-
</Box>
29-
</VStack>
23+
<Box overflowY="auto" h="100%" w="100%" padding={4}>
24+
<StatisticsView />
25+
</Box>
3026
);
3127
}
3228

@@ -35,15 +31,11 @@ export const SelectionView: React.FC = function () {
3531
}
3632

3733
return (
38-
<VStack h="100%" spacing={0}>
39-
<Box flexGrow={1} overflowY="auto" width="100%">
40-
<Box padding={4}>
41-
{declaration instanceof PythonFunction && <FunctionView pythonFunction={declaration} />}
42-
{declaration instanceof PythonClass && <ClassView pythonClass={declaration} />}
43-
{declaration instanceof PythonModule && <ModuleView pythonModule={declaration} />}
44-
{declaration instanceof PythonParameter && <ParameterView pythonParameter={declaration} />}
45-
</Box>
46-
</Box>
47-
</VStack>
34+
<Box overflowY="auto" h="100%" w="100%" padding={4}>
35+
{declaration instanceof PythonFunction && <FunctionView pythonFunction={declaration} />}
36+
{declaration instanceof PythonClass && <ClassView pythonClass={declaration} />}
37+
{declaration instanceof PythonModule && <ModuleView pythonModule={declaration} />}
38+
{declaration instanceof PythonParameter && <ParameterView pythonParameter={declaration} />}
39+
</Box>
4840
);
4941
};
Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
import { PythonPackage } from '../model/PythonPackage';
2+
import { PythonModule } from '../model/PythonModule';
3+
import { PythonClass } from '../model/PythonClass';
4+
import { PythonFunction } from '../model/PythonFunction';
5+
import { PythonParameter } from '../model/PythonParameter';
6+
import { UsageCountStore } from '../../usages/model/UsageCountStore';
7+
import { getClassValues, getFunctionValues, getParameterValues } from './StatisticsView';
8+
9+
const parameterTest: PythonParameter[] = [
10+
new PythonParameter(
11+
'test/test.test/parameterTestClass/privateParameterTestFunction/parameterTest0',
12+
'parameterTest0',
13+
'test.test.parameterTestClass.privateParameterTestFunction.parameterTest0',
14+
'',
15+
undefined,
16+
true,
17+
'',
18+
'',
19+
[],
20+
),
21+
new PythonParameter(
22+
'test/test.test/parameterTestClass/privateParameterTestFunction/parameterTest1',
23+
'parameterTest1',
24+
'test.test.parameterTestClass.privateParameterTestFunction.parameterTest1',
25+
'',
26+
undefined,
27+
true,
28+
'',
29+
'',
30+
[],
31+
),
32+
new PythonParameter(
33+
'test/test.test/parameterTestClass/privateParameterTestFunction/parameterTest2',
34+
'parameterTest2',
35+
'test.test.parameterTestClass.privateParameterTestFunction.parameterTest2',
36+
'',
37+
undefined,
38+
true,
39+
'',
40+
'',
41+
[],
42+
),
43+
];
44+
45+
const privateParameterTest: PythonParameter[] = [
46+
new PythonParameter(
47+
'test/test.test/parameterTestClass/privateParameterTestFunction/privateParameterTest',
48+
'privateParameterTest',
49+
'test.test.parameterTestClass.privateParameterTestFunction.privateParameterTest',
50+
'',
51+
undefined,
52+
false,
53+
'',
54+
'',
55+
[],
56+
),
57+
];
58+
59+
const testFunctions: PythonFunction[] = [
60+
new PythonFunction(
61+
'test/test.test/parameterTestClass/privateTestFunction',
62+
'privateTestFunction',
63+
'test.test.parameterTestClass.privateTestFunction',
64+
[],
65+
[],
66+
[],
67+
false,
68+
[],
69+
'',
70+
'',
71+
),
72+
new PythonFunction(
73+
'test/test.test/parameterTestClass/testFunction0',
74+
'testFunction0',
75+
'test.test.parameterTestClass.testFunction0',
76+
[],
77+
[],
78+
[],
79+
true,
80+
[],
81+
'',
82+
'',
83+
),
84+
new PythonFunction(
85+
'test/test.test/parameterTestClass/testFunction1',
86+
'testFunction1',
87+
'test.test.parameterTestClass.testFunction1',
88+
[],
89+
[],
90+
[],
91+
true,
92+
[],
93+
'',
94+
'',
95+
),
96+
new PythonFunction(
97+
'test/test.test/parameterTestClass/testFunction2',
98+
'testFunction2',
99+
'test.test.parameterTestClass.testFunction2',
100+
[],
101+
[],
102+
[],
103+
true,
104+
[],
105+
'',
106+
'',
107+
),
108+
];
109+
110+
const parameterTestFunctions: PythonFunction[] = [
111+
new PythonFunction(
112+
'test/test.test/parameterTestClass/privateParameterTestFunction',
113+
'privateParameterTestFunction',
114+
'test.test.parameterTestClass.privateParameterTestFunction',
115+
[],
116+
privateParameterTest,
117+
[],
118+
false,
119+
[],
120+
'',
121+
'',
122+
),
123+
new PythonFunction(
124+
'test/test.test/parameterTestClass/parameterTestFunction',
125+
'parameterTestFunction',
126+
'test.test.parameterTestClass.parameterTestFunction',
127+
[],
128+
parameterTest,
129+
[],
130+
true,
131+
[],
132+
'',
133+
'',
134+
),
135+
];
136+
137+
const testClasses: PythonClass[] = [
138+
new PythonClass(
139+
'test/test.test/privateClassTest',
140+
'privateClassTest',
141+
'test.test.privateClassTest',
142+
[],
143+
[],
144+
[],
145+
false,
146+
[],
147+
'',
148+
'',
149+
),
150+
new PythonClass('test/test.test/classTest0', 'classTest0', 'test.test.classTest0', [], [], [], true, [], '', ''),
151+
new PythonClass('test/test.test/classTest1', 'classTest1', 'test.test.classTest1', [], [], [], true, [], '', ''),
152+
new PythonClass('test/test.test/classTest2', 'classTest2', 'test.test.classTest2', [], [], [], true, [], '', ''),
153+
new PythonClass(
154+
'test/test.test/functionTestClass',
155+
'functionTestClass',
156+
'test.test.functionTestClass',
157+
[],
158+
[],
159+
testFunctions,
160+
true,
161+
[],
162+
'',
163+
'',
164+
),
165+
new PythonClass(
166+
'test/test.test/parameterTestClass',
167+
'parameterTestClass',
168+
'test.test.parameterTestClass',
169+
[],
170+
[],
171+
parameterTestFunctions,
172+
true,
173+
[],
174+
'',
175+
'',
176+
),
177+
];
178+
179+
const testModules = [new PythonModule('test/test.test', 'test.test', [], [], testClasses, [])];
180+
const pythonPackage = new PythonPackage('distribution', 'sklearn', 'version', testModules);
181+
/*--------------------------------------------------------------------------------------------------------------------*/
182+
183+
const parameterUsages = new Map([
184+
['test/test.test/parameterTestClass/privateParameterTestFunction/privateParameterTest', 1],
185+
['test/test.test/parameterTestClass/privateParameterTestFunction/parameterTest0', 0],
186+
['test/test.test/parameterTestClass/privateParameterTestFunction/parameterTest1', 1],
187+
['test/test.test/parameterTestClass/privateParameterTestFunction/parameterTest2', 2],
188+
]);
189+
190+
const functionUsages = new Map([
191+
['test/test.test/parameterTestClass/privateParameterTestFunction', 1],
192+
['test/test.test/parameterTestClass/parameterTestFunction', 0],
193+
['test/test.test/parameterTestClass/privateTestFunction', 1],
194+
['test/test.test/parameterTestClass/testFunction0', 0],
195+
['test/test.test/parameterTestClass/testFunction1', 1],
196+
['test/test.test/parameterTestClass/testFunction2', 2],
197+
]);
198+
199+
const classUsages = new Map([
200+
['test/test.test/privateClassTest', 1],
201+
['test/test.test/classTest0', 0],
202+
['test/test.test/classTest1', 1],
203+
['test/test.test/classTest2', 2],
204+
['test/test.test/functionTestClass', 0],
205+
['test/test.test/parameterTestClass', 0],
206+
]);
207+
208+
const moduleUsages = new Map([['test/test.test', 0]]);
209+
210+
const usages: UsageCountStore = new UsageCountStore(
211+
moduleUsages,
212+
classUsages,
213+
functionUsages,
214+
parameterUsages,
215+
new Map(),
216+
pythonPackage,
217+
);
218+
219+
const expectedClassCount = new Map([
220+
[0, [6, 5, 5]],
221+
[1, [6, 5, 2]],
222+
[3, [6, 5, 0]],
223+
]);
224+
225+
const expectedFunctionCount = new Map([
226+
[0, [6, 4, 4]],
227+
[1, [6, 4, 2]],
228+
[3, [6, 4, 0]],
229+
]);
230+
231+
const expectedParameterCount = new Map([
232+
[0, [4, 3, 3, 0]],
233+
[1, [4, 3, 2, 0]],
234+
[3, [4, 3, 0, 0]],
235+
]);
236+
237+
test('getClassValues', () => {
238+
for (const [usedThreshold, values] of Array.from(expectedClassCount.entries())) {
239+
expect(getClassValues(pythonPackage, usages, usedThreshold)).toEqual(values);
240+
}
241+
});
242+
243+
test('getFunctionValues', () => {
244+
for (const [usedThreshold, values] of Array.from(expectedFunctionCount.entries())) {
245+
expect(getFunctionValues(pythonPackage, usages, usedThreshold)).toEqual(values);
246+
}
247+
});
248+
249+
test('getParameterValues', () => {
250+
for (const [usedThreshold, values] of Array.from(expectedParameterCount.entries())) {
251+
expect(getParameterValues(pythonPackage, usages, usedThreshold)).toEqual(values);
252+
}
253+
});

0 commit comments

Comments
 (0)