Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Param groups. Collapsable Groups in UI #31

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 78 additions & 16 deletions src/components/FxParams/Controls.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { createRef, useEffect, useMemo, useState } from "react"
import React, { createRef, useEffect, useMemo, useState } from "react"
import { consolidateParams } from "components/FxParams/utils"
import { ParameterController } from "./Controller/Param"
import { LockButton } from "./LockButton/LockButton"
import classes from "./Controls.module.scss"
import { validateParameterDefinition } from "./validation"
import { stringifyParamsData } from "./utils"
import { FxParamType, FxParamTypeMap } from "./types.js"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import {
faChevronDown,
faChevronRight,
} from "@fortawesome/free-solid-svg-icons"
import { FxParamType, FxParamTypeMap } from "./types"

interface ControllerBladeProps {
parameter: any
Expand Down Expand Up @@ -33,7 +38,7 @@ function ControllerBlade(props: ControllerBladeProps) {
className={classes.lockButton}
title={`toggle lock ${parameter.id} param`}
isLocked={lockedParamIds?.includes(parameter.id)}
onClick={(e) => onClickLockButton(parameter.id)}
onClick={() => onClickLockButton(parameter.id)}
/>
)}
</div>
Expand Down Expand Up @@ -64,36 +69,93 @@ export const Controls = ({
onChangeData,
}: ControlsProps) => {
const consolidatedParams = consolidateParams(params, data)

const p: React.RefObject<HTMLDivElement> = createRef()
const [collapsedGroups, setCollapsedGroups] = useState<
Record<string, boolean>
>({})

const toggleGroup = (groupName: string) => {
setCollapsedGroups((prev) => ({
...prev,
[groupName]: !prev[groupName],
}))
}

useEffect(() => {
const ps: any = {}
if (consolidatedParams?.length > 0) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why this check was here but to reduce the area of potential failure of this PR we'd want to keep it, or explain how the check can be bypassed safely

consolidatedParams.forEach((p: any) => {
ps[p.id] = p.value
consolidatedParams.forEach((param: any) => {
ps[param.id] = param.value
})
if (stringifyParamsData(data) !== stringifyParamsData(ps))
if (stringifyParamsData(data) !== stringifyParamsData(ps)) {
onChangeData(ps)
}
}
}, [params])
}, [params, data, onChangeData])

const handleChangeParam = (id: string, value: any) => {
const newData = { ...data, [id]: value }
onChangeData(newData, { id, value })
}

const groupByGroup = (params: any[]) => {
return params.reduce((acc: { [key: string]: any[] }, param: any) => {
const groupName = param.group || "" // To-do: Maybe used "Other" as default group name? Nice when there are other groups but meaningless when no params have "group"
if (!acc[groupName]) {
acc[groupName] = []
}
acc[groupName].push(param)
return acc
}, {})
}

const groupedParams = useMemo(
() => groupByGroup(consolidatedParams),
[consolidatedParams]
)

const sortedGroupNames = useMemo(() => {
return Object.keys(groupedParams)
// To-do: decide if we want to sort A-Z or not. If so, we need to make sure "Other" is always last
// By now I'm leaving the order as it comes from the $fx.params() call so that the user is able to define its own custom sort order
return Object.keys(groupedParams).sort((a, b) => {
if (a === "Other") return 1
if (b === "Other") return -1
return a.localeCompare(b)
})
}, [groupedParams])

return (
<div className={classes.controls} ref={p}>
{consolidatedParams?.map((p: any) => {
{sortedGroupNames.map((groupName) => {
const isCollapsed = collapsedGroups[groupName]
return (
<ControllerBlade
key={p.id}
parameter={p}
onChangeParam={handleChangeParam}
lockedParamIds={lockedParamIds}
onClickLockButton={onClickLockButton}
/>
<div key={groupName} className={classes.group}>
<h3
onClick={() => toggleGroup(groupName)}
style={{
cursor: "pointer",
userSelect: "none",
display: "flex",
alignItems: "center",
}}
>
<FontAwesomeIcon
icon={isCollapsed ? faChevronRight : faChevronDown}
/>
<span style={{ marginLeft: "0.5em" }}>{groupName}</span>
</h3>
{!isCollapsed &&
groupedParams[groupName].map((param: any) => (
<ControllerBlade
key={param.id}
parameter={param}
onChangeParam={handleChangeParam}
lockedParamIds={lockedParamIds}
onClickLockButton={onClickLockButton}
/>
))}
</div>
)
})}
</div>
Expand Down