Skip to content

Commit 768c107

Browse files
committed
Make libraries collapsible
1 parent a833f78 commit 768c107

4 files changed

Lines changed: 129 additions & 16 deletions

File tree

extensions/ql-vscode/src/view/data-extensions-editor/DataExtensionsEditor.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { basename } from "../common/path";
1616
import { ViewTitle } from "../common";
1717
import { DataExtensionEditorViewState } from "../../data-extensions-editor/shared/view-state";
1818
import { ModeledMethodsList } from "./ModeledMethodsList";
19+
import { percentFormatter } from "./formatters";
1920

2021
const DataExtensionsEditorContainer = styled.div`
2122
margin-top: 1rem;
@@ -213,8 +214,12 @@ export function DataExtensionsEditor({
213214
)}
214215
</>
215216
)}
216-
<div>{modeledPercentage.toFixed(2)}% modeled</div>
217-
<div>{unModeledPercentage.toFixed(2)}% unmodeled</div>
217+
<div>
218+
{percentFormatter.format(modeledPercentage / 100)} modeled
219+
</div>
220+
<div>
221+
{percentFormatter.format(unModeledPercentage / 100)} unmodeled
222+
</div>
218223
</DetailsContainer>
219224

220225
<EditorContainer>
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import * as React from "react";
2+
import { useCallback, useMemo, useState } from "react";
3+
import styled from "styled-components";
4+
import { ExternalApiUsage } from "../../data-extensions-editor/external-api-usage";
5+
import { ModeledMethod } from "../../data-extensions-editor/modeled-method";
6+
import { ModeledMethodDataGrid } from "./ModeledMethodDataGrid";
7+
import { calculateModeledPercentage } from "./modeled";
8+
import { decimalFormatter, percentFormatter } from "./formatters";
9+
10+
const LibraryContainer = styled.div`
11+
margin-bottom: 1rem;
12+
`;
13+
14+
const TitleContainer = styled.button`
15+
display: flex;
16+
gap: 0.5em;
17+
align-items: center;
18+
width: 100%;
19+
font-size: 1.2em;
20+
font-weight: bold;
21+
22+
color: var(--vscode-editor-foreground);
23+
background-color: transparent;
24+
border: none;
25+
cursor: pointer;
26+
`;
27+
28+
const StatusContainer = styled.div`
29+
display: flex;
30+
gap: 1em;
31+
align-items: center;
32+
33+
margin-top: 0.5em;
34+
margin-bottom: 0.5em;
35+
margin-left: 1em;
36+
`;
37+
38+
type Props = {
39+
libraryName: string;
40+
externalApiUsages: ExternalApiUsage[];
41+
modeledMethods: Record<string, ModeledMethod>;
42+
onChange: (
43+
externalApiUsage: ExternalApiUsage,
44+
modeledMethod: ModeledMethod,
45+
) => void;
46+
};
47+
48+
export const LibraryRow = ({
49+
libraryName,
50+
externalApiUsages,
51+
modeledMethods,
52+
onChange,
53+
}: Props) => {
54+
const modeledPercentage = useMemo(() => {
55+
return calculateModeledPercentage(externalApiUsages);
56+
}, [externalApiUsages]);
57+
58+
const [isExpanded, setExpanded] = useState(modeledPercentage < 100);
59+
60+
const toggleExpanded = useCallback(async () => {
61+
setExpanded((oldIsExpanded) => !oldIsExpanded);
62+
}, []);
63+
64+
const usagesCount = useMemo(() => {
65+
return externalApiUsages.reduce((acc, curr) => acc + curr.usages.length, 0);
66+
}, [externalApiUsages]);
67+
68+
return (
69+
<LibraryContainer>
70+
<TitleContainer onClick={toggleExpanded} aria-expanded={isExpanded}>
71+
{libraryName}
72+
{isExpanded ? null : (
73+
<>
74+
{" "}
75+
({decimalFormatter.format(externalApiUsages.length)} method
76+
{externalApiUsages.length !== 1 ? "s" : ""},{" "}
77+
{percentFormatter.format(modeledPercentage / 100)} modeled)
78+
</>
79+
)}
80+
</TitleContainer>
81+
{isExpanded && (
82+
<>
83+
<StatusContainer>
84+
<div>
85+
{decimalFormatter.format(externalApiUsages.length)} method
86+
{externalApiUsages.length !== 1 ? "s" : ""}
87+
</div>
88+
<div>
89+
{decimalFormatter.format(usagesCount)} usage
90+
{usagesCount !== 1 ? "s" : ""}
91+
</div>
92+
<div>
93+
{percentFormatter.format(modeledPercentage / 100)} modeled
94+
</div>
95+
</StatusContainer>
96+
<ModeledMethodDataGrid
97+
externalApiUsages={externalApiUsages}
98+
modeledMethods={modeledMethods}
99+
onChange={onChange}
100+
/>
101+
</>
102+
)}
103+
</LibraryContainer>
104+
);
105+
};

extensions/ql-vscode/src/view/data-extensions-editor/ModeledMethodsList.tsx

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,9 @@
11
import * as React from "react";
22
import { useMemo } from "react";
3-
import styled from "styled-components";
43
import { ExternalApiUsage } from "../../data-extensions-editor/external-api-usage";
54
import { ModeledMethod } from "../../data-extensions-editor/modeled-method";
6-
import { ModeledMethodDataGrid } from "./ModeledMethodDataGrid";
75
import { calculateModeledPercentage } from "./modeled";
8-
9-
const LibraryContainer = styled.div`
10-
margin-bottom: 1rem;
11-
`;
6+
import { LibraryRow } from "./LibraryRow";
127

138
type Props = {
149
externalApiUsages: ExternalApiUsage[];
@@ -69,14 +64,13 @@ export const ModeledMethodsList = ({
6964
return (
7065
<>
7166
{sortedLibraryNames.map((libraryName) => (
72-
<LibraryContainer key={libraryName}>
73-
<h3>{libraryName}</h3>
74-
<ModeledMethodDataGrid
75-
externalApiUsages={groupedByLibrary[libraryName]}
76-
modeledMethods={modeledMethods}
77-
onChange={onChange}
78-
/>
79-
</LibraryContainer>
67+
<LibraryRow
68+
key={libraryName}
69+
libraryName={libraryName}
70+
externalApiUsages={groupedByLibrary[libraryName]}
71+
modeledMethods={modeledMethods}
72+
onChange={onChange}
73+
/>
8074
))}
8175
</>
8276
);
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export const decimalFormatter = new Intl.NumberFormat("en-US", {
2+
style: "decimal",
3+
maximumFractionDigits: 2,
4+
});
5+
6+
export const percentFormatter = new Intl.NumberFormat("en-US", {
7+
style: "percent",
8+
maximumFractionDigits: 2,
9+
});

0 commit comments

Comments
 (0)