Make libraries collapsible
This commit is contained in:
@@ -16,6 +16,7 @@ import { basename } from "../common/path";
|
||||
import { ViewTitle } from "../common";
|
||||
import { DataExtensionEditorViewState } from "../../data-extensions-editor/shared/view-state";
|
||||
import { ModeledMethodsList } from "./ModeledMethodsList";
|
||||
import { percentFormatter } from "./formatters";
|
||||
|
||||
const DataExtensionsEditorContainer = styled.div`
|
||||
margin-top: 1rem;
|
||||
@@ -213,8 +214,12 @@ export function DataExtensionsEditor({
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<div>{modeledPercentage.toFixed(2)}% modeled</div>
|
||||
<div>{unModeledPercentage.toFixed(2)}% unmodeled</div>
|
||||
<div>
|
||||
{percentFormatter.format(modeledPercentage / 100)} modeled
|
||||
</div>
|
||||
<div>
|
||||
{percentFormatter.format(unModeledPercentage / 100)} unmodeled
|
||||
</div>
|
||||
</DetailsContainer>
|
||||
|
||||
<EditorContainer>
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
import * as React from "react";
|
||||
import { useCallback, useMemo, useState } from "react";
|
||||
import styled from "styled-components";
|
||||
import { ExternalApiUsage } from "../../data-extensions-editor/external-api-usage";
|
||||
import { ModeledMethod } from "../../data-extensions-editor/modeled-method";
|
||||
import { ModeledMethodDataGrid } from "./ModeledMethodDataGrid";
|
||||
import { calculateModeledPercentage } from "./modeled";
|
||||
import { decimalFormatter, percentFormatter } from "./formatters";
|
||||
|
||||
const LibraryContainer = styled.div`
|
||||
margin-bottom: 1rem;
|
||||
`;
|
||||
|
||||
const TitleContainer = styled.button`
|
||||
display: flex;
|
||||
gap: 0.5em;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
font-size: 1.2em;
|
||||
font-weight: bold;
|
||||
|
||||
color: var(--vscode-editor-foreground);
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
`;
|
||||
|
||||
const StatusContainer = styled.div`
|
||||
display: flex;
|
||||
gap: 1em;
|
||||
align-items: center;
|
||||
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 0.5em;
|
||||
margin-left: 1em;
|
||||
`;
|
||||
|
||||
type Props = {
|
||||
libraryName: string;
|
||||
externalApiUsages: ExternalApiUsage[];
|
||||
modeledMethods: Record<string, ModeledMethod>;
|
||||
onChange: (
|
||||
externalApiUsage: ExternalApiUsage,
|
||||
modeledMethod: ModeledMethod,
|
||||
) => void;
|
||||
};
|
||||
|
||||
export const LibraryRow = ({
|
||||
libraryName,
|
||||
externalApiUsages,
|
||||
modeledMethods,
|
||||
onChange,
|
||||
}: Props) => {
|
||||
const modeledPercentage = useMemo(() => {
|
||||
return calculateModeledPercentage(externalApiUsages);
|
||||
}, [externalApiUsages]);
|
||||
|
||||
const [isExpanded, setExpanded] = useState(modeledPercentage < 100);
|
||||
|
||||
const toggleExpanded = useCallback(async () => {
|
||||
setExpanded((oldIsExpanded) => !oldIsExpanded);
|
||||
}, []);
|
||||
|
||||
const usagesCount = useMemo(() => {
|
||||
return externalApiUsages.reduce((acc, curr) => acc + curr.usages.length, 0);
|
||||
}, [externalApiUsages]);
|
||||
|
||||
return (
|
||||
<LibraryContainer>
|
||||
<TitleContainer onClick={toggleExpanded} aria-expanded={isExpanded}>
|
||||
{libraryName}
|
||||
{isExpanded ? null : (
|
||||
<>
|
||||
{" "}
|
||||
({decimalFormatter.format(externalApiUsages.length)} method
|
||||
{externalApiUsages.length !== 1 ? "s" : ""},{" "}
|
||||
{percentFormatter.format(modeledPercentage / 100)} modeled)
|
||||
</>
|
||||
)}
|
||||
</TitleContainer>
|
||||
{isExpanded && (
|
||||
<>
|
||||
<StatusContainer>
|
||||
<div>
|
||||
{decimalFormatter.format(externalApiUsages.length)} method
|
||||
{externalApiUsages.length !== 1 ? "s" : ""}
|
||||
</div>
|
||||
<div>
|
||||
{decimalFormatter.format(usagesCount)} usage
|
||||
{usagesCount !== 1 ? "s" : ""}
|
||||
</div>
|
||||
<div>
|
||||
{percentFormatter.format(modeledPercentage / 100)} modeled
|
||||
</div>
|
||||
</StatusContainer>
|
||||
<ModeledMethodDataGrid
|
||||
externalApiUsages={externalApiUsages}
|
||||
modeledMethods={modeledMethods}
|
||||
onChange={onChange}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</LibraryContainer>
|
||||
);
|
||||
};
|
||||
@@ -1,14 +1,9 @@
|
||||
import * as React from "react";
|
||||
import { useMemo } from "react";
|
||||
import styled from "styled-components";
|
||||
import { ExternalApiUsage } from "../../data-extensions-editor/external-api-usage";
|
||||
import { ModeledMethod } from "../../data-extensions-editor/modeled-method";
|
||||
import { ModeledMethodDataGrid } from "./ModeledMethodDataGrid";
|
||||
import { calculateModeledPercentage } from "./modeled";
|
||||
|
||||
const LibraryContainer = styled.div`
|
||||
margin-bottom: 1rem;
|
||||
`;
|
||||
import { LibraryRow } from "./LibraryRow";
|
||||
|
||||
type Props = {
|
||||
externalApiUsages: ExternalApiUsage[];
|
||||
@@ -69,14 +64,13 @@ export const ModeledMethodsList = ({
|
||||
return (
|
||||
<>
|
||||
{sortedLibraryNames.map((libraryName) => (
|
||||
<LibraryContainer key={libraryName}>
|
||||
<h3>{libraryName}</h3>
|
||||
<ModeledMethodDataGrid
|
||||
externalApiUsages={groupedByLibrary[libraryName]}
|
||||
modeledMethods={modeledMethods}
|
||||
onChange={onChange}
|
||||
/>
|
||||
</LibraryContainer>
|
||||
<LibraryRow
|
||||
key={libraryName}
|
||||
libraryName={libraryName}
|
||||
externalApiUsages={groupedByLibrary[libraryName]}
|
||||
modeledMethods={modeledMethods}
|
||||
onChange={onChange}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
export const decimalFormatter = new Intl.NumberFormat("en-US", {
|
||||
style: "decimal",
|
||||
maximumFractionDigits: 2,
|
||||
});
|
||||
|
||||
export const percentFormatter = new Intl.NumberFormat("en-US", {
|
||||
style: "percent",
|
||||
maximumFractionDigits: 2,
|
||||
});
|
||||
Reference in New Issue
Block a user