From 59ecec2b7b188c271123bbe55706f9a55d309112 Mon Sep 17 00:00:00 2001 From: Romain Tetley Date: Wed, 11 Dec 2024 10:52:10 +0100 Subject: [PATCH] feat: add a secondary action to the accordion + allow toggle goal context When a goal is expanded, a secondary action appears next to the collapse/expand button. This button represented by a closed/open eye allows to show/hide the goal context (hyps). --- client/goal-view-ui/src/App.tsx | 30 ++++++++++++++----- .../src/components/atoms/Accordion.tsx | 18 ++++++++--- .../molecules/CollapsibleGoalBlock.tsx | 18 ++++++++--- .../src/components/molecules/GoalBlock.tsx | 6 ++-- .../components/organisms/GoalCollapsibles.tsx | 19 ++++++++++-- .../src/components/organisms/GoalSection.tsx | 16 +++++++--- .../{ProovViewPage.tsx => ProofViewPage.tsx} | 24 ++++++++++----- client/goal-view-ui/src/types.ts | 1 + 8 files changed, 99 insertions(+), 33 deletions(-) rename client/goal-view-ui/src/components/templates/{ProovViewPage.tsx => ProofViewPage.tsx} (85%) diff --git a/client/goal-view-ui/src/App.tsx b/client/goal-view-ui/src/App.tsx index 20e0fec3..d99fce02 100644 --- a/client/goal-view-ui/src/App.tsx +++ b/client/goal-view-ui/src/App.tsx @@ -1,7 +1,7 @@ import React, {useState, useCallback, useEffect} from 'react'; import "./App.css"; -import ProofViewPage from './components/templates/ProovViewPage'; +import ProofViewPage from './components/templates/ProofViewPage'; import {Goal, ProofViewGoals, ProofViewGoalsKey, ProofViewMessage} from './types'; import { vscode } from "./utilities/vscode"; @@ -30,16 +30,16 @@ const app = () => { ? allGoals : { main: allGoals.goals.map((goal: Goal, index: number) => { - return {...goal, isOpen: true}; + return {...goal, isOpen: true, isContextHidden: index !== 0}; }), - shelved: allGoals.shelvedGoals.map((goal: Goal) => { - return {...goal, isOpen: true}; + shelved: allGoals.shelvedGoals.map((goal: Goal, index: number) => { + return {...goal, isOpen: true, isContextHidden: index !== 0}; }), - givenUp: allGoals.givenUpGoals.map((goal: Goal) => { - return {...goal, isOpen: true}; + givenUp: allGoals.givenUpGoals.map((goal: Goal, index: number) => { + return {...goal, isOpen: true, isContextHidden: index !== 0}; }), - unfocused: allGoals.unfocusedGoals.map((goal: Goal) => { - return {...goal, isOpen: false}; + unfocused: allGoals.unfocusedGoals.map((goal: Goal, index: number) => { + return {...goal, isOpen: false, isContextHidden: index !== 0}; }) } ); @@ -72,6 +72,19 @@ const app = () => { }); }; + const toggleContext = (id: string, key: ProofViewGoalsKey) => { + const newGoals = goals![key].map(goal => { + if(goal.id === id){ + return {...goal, isContextHidden: !goal.isContextHidden}; + } + return goal; + }); + setGoals({ + ...goals!, + [key]: newGoals + }); + }; + const settingsClickHandler = () => { vscode.postMessage({ command: "openGoalSettings", @@ -89,6 +102,7 @@ const app = () => { settingsClickHandler={settingsClickHandler} helpMessage={helpMessage} helpMessageHandler={(message: string) => setHelpMessage(message)} + toggleContextHandler={toggleContext} /> ); diff --git a/client/goal-view-ui/src/components/atoms/Accordion.tsx b/client/goal-view-ui/src/components/atoms/Accordion.tsx index 9020a2f8..9d92d3ad 100644 --- a/client/goal-view-ui/src/components/atoms/Accordion.tsx +++ b/client/goal-view-ui/src/components/atoms/Accordion.tsx @@ -8,11 +8,13 @@ type AccordionProps = { collapsed: boolean; title: string; collapseHandler?: (params: any) => void; + seconaryActionHandler?: (params: any) => void; + seconaryActionIcon?: JSX.Element; }; const accordion: FunctionComponent = (props) => { - const {title, collapseHandler} = props; + const {title, collapseHandler, seconaryActionHandler, seconaryActionIcon} = props; const [collapsed, setCollapsed] = useState(props.collapsed); useEffect(() => { setCollapsed(props.collapsed); @@ -25,15 +27,23 @@ const accordion: FunctionComponent = (props) => { const toggleCollapse = collapseHandler ? collapseHandler : () => setCollapsed(!collapsed); + const secondaryActionButton = (seconaryActionHandler !== undefined && seconaryActionIcon !== undefined) ? {seconaryActionIcon} : null; + const secondaryAction = collapsed ? null : secondaryActionButton; + const actionRow = +
+ {secondaryAction} + + + +
; + return (
{/* The header with title and button */}
{title} - - - + {actionRow}
{/* The panel that collapses */} diff --git a/client/goal-view-ui/src/components/molecules/CollapsibleGoalBlock.tsx b/client/goal-view-ui/src/components/molecules/CollapsibleGoalBlock.tsx index 5bcb6fda..2482b7b1 100644 --- a/client/goal-view-ui/src/components/molecules/CollapsibleGoalBlock.tsx +++ b/client/goal-view-ui/src/components/molecules/CollapsibleGoalBlock.tsx @@ -1,12 +1,15 @@ import React, {FunctionComponent} from 'react'; +import { VscEye, VscEyeClosed } from 'react-icons/vsc'; + import GoalBlock from './GoalBlock'; import Accordion from '../atoms/Accordion'; import { CollapsibleGoal } from '../../types'; type CollapsibleGoalBlockProps = { goal: CollapsibleGoal, - collapseHandler: (id: string) => void, + collapseHandler: (id: string) => void, + toggleContextHandler: (id:string) => void, goalIndex: number, goalIndicator: string, maxDepth: number, @@ -15,11 +18,18 @@ type CollapsibleGoalBlockProps = { const collapsibleGoalBlock: FunctionComponent = (props) => { - const {goal, goalIndex, goalIndicator, collapseHandler, maxDepth, helpMessageHandler} = props; + const {goal, goalIndex, goalIndicator, collapseHandler, toggleContextHandler, maxDepth, helpMessageHandler} = props; + + const secondaryActionIcon = goal.isContextHidden ? : ; + const secondaryActionHandler = toggleContextHandler !== undefined ? () => toggleContextHandler(goal.id) : undefined; return ( - collapseHandler(goal.id)}> - + collapseHandler(goal.id)} + seconaryActionHandler={secondaryActionHandler} + seconaryActionIcon={secondaryActionIcon} + > + ); diff --git a/client/goal-view-ui/src/components/molecules/GoalBlock.tsx b/client/goal-view-ui/src/components/molecules/GoalBlock.tsx index c47d5c01..7d1fb9fa 100644 --- a/client/goal-view-ui/src/components/molecules/GoalBlock.tsx +++ b/client/goal-view-ui/src/components/molecules/GoalBlock.tsx @@ -20,12 +20,14 @@ const goalBlock: FunctionComponent = (props) => { const {goal, goalIndicator, maxDepth, displayHyps, helpMessageHandler} = props; const indicator = goalIndicator ? ({goalIndicator}) : null; const hyps = displayHyps ? : null; - const sep = displayHyps ?
{indicator}
: null; return (
{hyps} - {sep} +
+ {indicator} + +
); diff --git a/client/goal-view-ui/src/components/organisms/GoalCollapsibles.tsx b/client/goal-view-ui/src/components/organisms/GoalCollapsibles.tsx index 75034f56..be08bfb8 100644 --- a/client/goal-view-ui/src/components/organisms/GoalCollapsibles.tsx +++ b/client/goal-view-ui/src/components/organisms/GoalCollapsibles.tsx @@ -8,13 +8,14 @@ import classes from './GoalCollapsibles.module.css'; type GoalSectionProps = { goals: CollapsibleGoal[], collapseGoalHandler: (id: string) => void, + toggleContextHandler: (id: string) => void, maxDepth: number, helpMessageHandler: (message: string) => void }; const goalSection: FunctionComponent = (props) => { - const {goals, collapseGoalHandler, maxDepth, helpMessageHandler} = props; + const {goals, collapseGoalHandler, toggleContextHandler, maxDepth, helpMessageHandler} = props; const firstGoalRef = useRef(null); useEffect(() => { @@ -36,14 +37,26 @@ const goalSection: FunctionComponent = (props) => { if(index === 0) { return ( <> - +
); } return ( - + ); }); diff --git a/client/goal-view-ui/src/components/organisms/GoalSection.tsx b/client/goal-view-ui/src/components/organisms/GoalSection.tsx index 2598cd63..fec57f6a 100644 --- a/client/goal-view-ui/src/components/organisms/GoalSection.tsx +++ b/client/goal-view-ui/src/components/organisms/GoalSection.tsx @@ -9,7 +9,8 @@ import classes from './GoalSection.module.css'; type GoalSectionProps = { goals: CollapsibleGoal[], - collapseGoalHandler: (id: string) => void, + collapseGoalHandler: (id: string) => void, + toggleContextHandler: (id: string) => void, displaySetting: string; emptyMessage: string; emptyIcon?: JSX.Element; @@ -20,7 +21,7 @@ type GoalSectionProps = { const goalSection: FunctionComponent = (props) => { - const {goals, collapseGoalHandler, displaySetting, unfocusedGoals, emptyMessage, emptyIcon, maxDepth, helpMessageHandler} = props; + const {goals, collapseGoalHandler, toggleContextHandler, displaySetting, unfocusedGoals, emptyMessage, emptyIcon, maxDepth, helpMessageHandler} = props; const emptyMessageRef = useRef(null); useEffect(() => { @@ -46,7 +47,10 @@ const goalSection: FunctionComponent = (props) => { Next unfocused goals (focus with bullet):
- +
: <> @@ -54,7 +58,11 @@ const goalSection: FunctionComponent = (props) => { : displaySetting === 'Tabs' ? - : ; + : ; return section; }; diff --git a/client/goal-view-ui/src/components/templates/ProovViewPage.tsx b/client/goal-view-ui/src/components/templates/ProofViewPage.tsx similarity index 85% rename from client/goal-view-ui/src/components/templates/ProovViewPage.tsx rename to client/goal-view-ui/src/components/templates/ProofViewPage.tsx index 46e6ce24..d93717dc 100644 --- a/client/goal-view-ui/src/components/templates/ProovViewPage.tsx +++ b/client/goal-view-ui/src/components/templates/ProofViewPage.tsx @@ -20,9 +20,10 @@ import classes from './GoalPage.module.css'; import { VscPass, VscWarning } from 'react-icons/vsc'; type ProofViewPageProps = { - goals: ProofViewGoals, - messages: ProofViewMessage[], - collapseGoalHandler: (id: string, key: ProofViewGoalsKey) => void, + goals: ProofViewGoals; + messages: ProofViewMessage[]; + collapseGoalHandler: (id: string, key: ProofViewGoalsKey) => void; + toggleContextHandler: (id: string, key: ProofViewGoalsKey) => void; displaySetting: string; maxDepth: number; settingsClickHandler: () => void; @@ -32,7 +33,11 @@ type ProofViewPageProps = { const proofViewPage: FunctionComponent = (props) => { - const {goals, messages, displaySetting, collapseGoalHandler, maxDepth, settingsClickHandler, helpMessage, helpMessageHandler} = props; + const {goals, messages, displaySetting, + collapseGoalHandler, maxDepth, settingsClickHandler, + helpMessage, helpMessageHandler, + toggleContextHandler, + } = props; const renderGoals = () => { const goalBadge = {goals!.main.length}; @@ -52,6 +57,7 @@ const proofViewPage: FunctionComponent = (props) => { goals={goals!.main} unfocusedGoals={goals!.unfocused} collapseGoalHandler={(id) => collapseGoalHandler(id, goals!.main.length ? ProofViewGoalsKey.main : ProofViewGoalsKey.unfocused)} + toggleContextHandler={(id) => toggleContextHandler(id, goals!.main.length ? ProofViewGoalsKey.main : ProofViewGoalsKey.unfocused)} displaySetting={displaySetting} emptyMessage={ goals!.shelved.length ? "There are shelved goals. Try using `Unshelve.`" : @@ -69,8 +75,9 @@ const proofViewPage: FunctionComponent = (props) => { collapseGoalHandler(id, ProofViewGoalsKey.shelved)} + goals={goals!.shelved} + collapseGoalHandler={(id) => collapseGoalHandler(id, ProofViewGoalsKey.shelved)} + toggleContextHandler={(id) => toggleContextHandler(id, ProofViewGoalsKey.shelved)} displaySetting={displaySetting} emptyMessage='There are no shelved goals' maxDepth={maxDepth} @@ -80,8 +87,9 @@ const proofViewPage: FunctionComponent = (props) => { collapseGoalHandler(id, ProofViewGoalsKey.givenUp)} + goals={goals!.givenUp} + collapseGoalHandler={(id) => collapseGoalHandler(id, ProofViewGoalsKey.givenUp)} + toggleContextHandler={(id) => toggleContextHandler(id, ProofViewGoalsKey.givenUp)} displaySetting={displaySetting} emptyMessage='There are no given up goals' maxDepth={maxDepth} diff --git a/client/goal-view-ui/src/types.ts b/client/goal-view-ui/src/types.ts index 866af31d..efeb0ba1 100644 --- a/client/goal-view-ui/src/types.ts +++ b/client/goal-view-ui/src/types.ts @@ -10,6 +10,7 @@ export interface Goal { export interface CollapsibleGoal extends Goal { isOpen: boolean; + isContextHidden: boolean; }; export type ProofViewGoalsType = {