Skip to content

Commit

Permalink
Basic Accordion Implementation for Catalog, no styling
Browse files Browse the repository at this point in the history
  • Loading branch information
thsparks committed May 7, 2024
1 parent 1b0949c commit ea2a2af
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 29 deletions.
5 changes: 5 additions & 0 deletions common-docs/teachertool/catalog-shared.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"template": "${Block} used ${count} times",
"description": "This block was used the specified number of times in your project.",
"docPath": "/teachertool",
"tags": ["General"],
"params": [
{
"name": "block",
Expand All @@ -27,6 +28,7 @@
"description": "The project contains at least the specified number of comments.",
"docPath": "/teachertool",
"maxCount": 1,
"tags": ["General"],
"params": [
{
"name": "count",
Expand All @@ -43,6 +45,7 @@
"docPath": "/teachertool",
"description": "The program uses at least this many loops of any kind (for, repeat, while, or for-of).",
"maxCount": 1,
"tags": ["Code Elements"],
"params": [
{
"name": "count",
Expand All @@ -59,6 +62,7 @@
"docPath": "/teachertool",
"description": "At least this many user-defined functions are created and called.",
"maxCount": 1,
"tags": ["Code Elements"],
"params": [
{
"name": "count",
Expand All @@ -75,6 +79,7 @@
"docPath": "/teachertool",
"description": "The program creates and uses at least this many user-defined variables.",
"maxCount": 1,
"tags": ["Code Elements"],
"params": [
{
"name": "count",
Expand Down
1 change: 1 addition & 0 deletions common-docs/teachertool/test/catalog-shared.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"description": "Experimental: AI outputs may not be accurate. Use with caution and always review responses.",
"docPath": "/teachertool",
"maxCount": 10,
"tags": ["General"],
"params": [
{
"name": "question",
Expand Down
81 changes: 53 additions & 28 deletions teachertool/src/components/CatalogOverlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@ import { getCatalogCriteria } from "../state/helpers";
import { ReadOnlyCriteriaDisplay } from "./ReadonlyCriteriaDisplay";
import { Strings } from "../constants";
import { Button } from "react-common/components/controls/Button";
import { Accordion } from "react-common/components/controls/Accordion";
import { getReadableCriteriaTemplate, makeToast } from "../utils";
import { setCatalogOpen } from "../transforms/setCatalogOpen";
import { classList } from "react-common/components/util";
import { announceToScreenReader } from "../transforms/announceToScreenReader";
import { FocusTrap } from "react-common/components/controls/FocusTrap";
import css from "./styling/CatalogOverlay.module.scss";
import { logError } from "../services/loggingService";
import { ErrorCode } from "../types/errorCode";
import { AccordionHeader, AccordionItem, AccordionPanel } from "react-common/components/controls/Accordion/Accordion";

interface CatalogHeaderProps {
onClose: () => void;
Expand Down Expand Up @@ -73,10 +77,22 @@ const CatalogList: React.FC = () => {
const recentlyAddedWindowMs = 500;
const [recentlyAddedIds, setRecentlyAddedIds] = useState<pxsim.Map<NodeJS.Timeout>>({});

const criteria = useMemo<CatalogCriteria[]>(
() => getCatalogCriteria(teacherTool),
[teacherTool.catalog, teacherTool.checklist]
);
// For now, we only look at the first tag of each criteria.
const criteriaGroupedByTag = useMemo<pxt.Map<CatalogCriteria[]>>(() => {
const grouped: pxt.Map<CatalogCriteria[]> = {};
getCatalogCriteria(teacherTool)?.forEach(c => {
const tag = c.tags?.[0];
if (!tag) {
logError(ErrorCode.missingTag, { message: "Catalog criteria missing tag", criteria: c });
return;
}
if (!grouped[tag]) {
grouped[tag] = [];
}
grouped[tag].push(c);
});
return grouped;
}, [teacherTool.catalog]);

function updateRecentlyAddedValue(id: string, value: NodeJS.Timeout | undefined) {
setRecentlyAddedIds(prevState => {
Expand Down Expand Up @@ -107,33 +123,42 @@ const CatalogList: React.FC = () => {
}

return (
<div className={css["catalog-list"]}>
{criteria.map(c => {
const existingInstanceCount = teacherTool.checklist.criteria.filter(
i => i.catalogCriteriaId === c.id
).length;
const isMaxed = c.maxCount !== undefined && existingInstanceCount >= c.maxCount;
<Accordion className={css["catalog-list"]}>
{Object.keys(criteriaGroupedByTag).map(tag => {
return (
c.template && (
<Button
id={`criteria_${c.id}`}
title={getReadableCriteriaTemplate(c)}
key={c.id}
className={css["catalog-item"]}
label={
<CatalogItemLabel
catalogCriteria={c}
isMaxed={isMaxed}
recentlyAdded={recentlyAddedIds[c.id] !== undefined}
/>
}
onClick={() => onItemClicked(c)}
disabled={isMaxed}
/>
)
<Accordion.Item>
<Accordion.Header>{tag}</Accordion.Header>
<Accordion.Panel>
{criteriaGroupedByTag[tag].map(c => {
const existingInstanceCount = teacherTool.checklist.criteria.filter(
i => i.catalogCriteriaId === c.id
).length;
const isMaxed = c.maxCount !== undefined && existingInstanceCount >= c.maxCount;
return (
c.template && (
<Button
id={`criteria_${c.id}`}
title={getReadableCriteriaTemplate(c)}
key={c.id}
className={css["catalog-item"]}
label={
<CatalogItemLabel
catalogCriteria={c}
isMaxed={isMaxed}
recentlyAdded={recentlyAddedIds[c.id] !== undefined}
/>
}
onClick={() => onItemClicked(c)}
disabled={isMaxed}
/>
)
);
})}
</Accordion.Panel>
</Accordion.Item>
);
})}
</div>
</Accordion>
);
};

Expand Down
7 changes: 6 additions & 1 deletion teachertool/src/transforms/loadCatalogAsync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,16 @@ export async function loadCatalogAsync() {
const { dispatch } = stateAndDispatch();
const fullCatalog = await loadTestableCollectionFromDocsAsync<CatalogCriteria>(prodFiles, "criteria");

// Convert parameter names to lower-case for case-insensitive matching
fullCatalog.forEach(c => {
// Convert parameter names to lower-case for case-insensitive matching
c.params?.forEach(p => {
p.name = p.name.toLocaleLowerCase();
});

// Add default tag if none are present
if (!c.tags || c.tags.length === 0) {
c.tags = ["Other"];
}
});

dispatch(Actions.setCatalog(fullCatalog));
Expand Down
1 change: 1 addition & 0 deletions teachertool/src/types/criteria.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export interface CatalogCriteria {
params: CriteriaParameter[] | undefined; // Any parameters that affect the criteria
hideInCatalog?: boolean; // Whether the criteria should be hidden in the user-facing catalog
maxCount?: number; // The maximum number of instances allowed for this criteria within a single checklist. Unlimited if undefined.
tags?: string[]; // Tags to help categorize the criteria
}

// An instance of a criteria in a checklist.
Expand Down
1 change: 1 addition & 0 deletions teachertool/src/types/errorCode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ export enum ErrorCode {
unrecognizedSystemParameter = "unrecognizedSystemParameter",
invalidValidatorPlan = "invalidValidatorPlan",
askCopilotQuestion = "askCopilotQuestion",
missingTag = "missingTag",
}

0 comments on commit ea2a2af

Please sign in to comment.