From 7aedd3287170f6bae398a18457b4e69af721c187 Mon Sep 17 00:00:00 2001 From: Cody O'Donnell Date: Fri, 2 Aug 2024 15:26:32 -0700 Subject: [PATCH 1/5] Fix import and change package to public --- strudel-components/lib/components/FilterGroup.tsx | 2 +- strudel-components/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/strudel-components/lib/components/FilterGroup.tsx b/strudel-components/lib/components/FilterGroup.tsx index 4680fed3..ada07185 100644 --- a/strudel-components/lib/components/FilterGroup.tsx +++ b/strudel-components/lib/components/FilterGroup.tsx @@ -1,6 +1,6 @@ import ArrowForwardIosSharpIcon from '@mui/icons-material/ArrowForwardIosSharp'; import { Accordion, AccordionDetails, AccordionSummary, Chip, Stack, Typography } from '@mui/material'; -import React, { useState } from 'react'; +import React from 'react'; import { useFilters } from './FilterContext'; import { hasValue } from './FilterField'; diff --git a/strudel-components/package.json b/strudel-components/package.json index 6e41ad7e..f17f7b62 100644 --- a/strudel-components/package.json +++ b/strudel-components/package.json @@ -1,6 +1,6 @@ { "name": "@strudel-science/components", - "private": true, + "private": false, "version": "0.0.1", "type": "module", "repository": { From dfee2e6023843bf2dc6d3d5d874516abedf2e68c Mon Sep 17 00:00:00 2001 From: Cody O'Donnell Date: Fri, 2 Aug 2024 15:35:56 -0700 Subject: [PATCH 2/5] Fix main entry point for package --- strudel-components/package-lock.json | 4 ++-- strudel-components/package.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/strudel-components/package-lock.json b/strudel-components/package-lock.json index 7e1d6789..8fcddcda 100644 --- a/strudel-components/package-lock.json +++ b/strudel-components/package-lock.json @@ -1,12 +1,12 @@ { "name": "@strudel-science/components", - "version": "0.0.1", + "version": "0.0.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@strudel-science/components", - "version": "0.0.1", + "version": "0.0.2", "devDependencies": { "@react-docgen/cli": "^2.0.3", "@types/node": "^20.12.7", diff --git a/strudel-components/package.json b/strudel-components/package.json index f17f7b62..c18b7194 100644 --- a/strudel-components/package.json +++ b/strudel-components/package.json @@ -1,7 +1,7 @@ { "name": "@strudel-science/components", "private": false, - "version": "0.0.1", + "version": "0.0.2", "type": "module", "repository": { "type": "git", @@ -15,7 +15,7 @@ "preview": "vite preview", "docgen": "react-docgen" }, - "main": "dist/strudel-components.js", + "main": "dist/components.js", "types": "dist/main.d.ts", "files": [ "dist" From 2039499c587686c97dff1844c8053ed8df7dc9e7 Mon Sep 17 00:00:00 2001 From: Cody O'Donnell Date: Thu, 15 Aug 2024 13:38:56 -0700 Subject: [PATCH 3/5] Add operator to activeFilters in Filters component and change to array --- .../lib/components/CheckboxList.tsx | 1 + .../lib/components/FilterContext.tsx | 37 ++- .../lib/components/FilterField.tsx | 33 ++- strudel-components/lib/components/Filters.tsx | 13 +- strudel-components/src/App.tsx | 4 +- .../examples/Filters/FiltersExNoGroups.tsx | 7 + strudel-taskflows/package-lock.json | 274 +++++++++++------- .../explore-data/_components/FiltersPanel.tsx | 82 +----- .../explore-data/_config/taskflow.config.ts | 32 +- .../explore-data/_config/taskflow.types.ts | 8 +- .../explore-data/_context/ContextProvider.tsx | 6 + .../pages/explore-data/_context/actions.ts | 6 + strudel-taskflows/src/pages/index.tsx | 4 +- strudel-taskflows/src/utils/filters.utils.ts | 10 +- 14 files changed, 297 insertions(+), 220 deletions(-) diff --git a/strudel-components/lib/components/CheckboxList.tsx b/strudel-components/lib/components/CheckboxList.tsx index dd58986e..a3b40d73 100644 --- a/strudel-components/lib/components/CheckboxList.tsx +++ b/strudel-components/lib/components/CheckboxList.tsx @@ -39,6 +39,7 @@ export const CheckboxList: React.FC = ({ }; useEffect(() => { + console.log(checkValues) if (onChange) onChange(checkValues); }, [checkValues]); diff --git a/strudel-components/lib/components/FilterContext.tsx b/strudel-components/lib/components/FilterContext.tsx index 86d2e7ae..2f790884 100644 --- a/strudel-components/lib/components/FilterContext.tsx +++ b/strudel-components/lib/components/FilterContext.tsx @@ -1,29 +1,52 @@ import React, { PropsWithChildren, useContext, useEffect, useReducer } from 'react'; +import { FilterOperator } from './FilterField'; + +export interface DataFilter { + field: string; + value: string | any[] | null; + operator: FilterOperator; +} export interface FilterState { - activeFilters: { [key: string]: any } + activeFilters: DataFilter[]; expandedGroup: string | number | boolean; } const FilterContextAPI = React.createContext<{state: FilterState; dispatch: React.Dispatch} | undefined>(undefined); const initialState: FilterState = { - activeFilters: {}, + activeFilters: [], expandedGroup: false, } export type FilterAction = - | { type: 'SET_FILTER', payload: { field: string, value: any } } - | { type: 'SET_ACTIVE_FILTERS', payload:FilterState['activeFilters'] } + | { type: 'SET_FILTER', payload: { field: string, value: any, operator: FilterOperator } } + | { type: 'SET_ACTIVE_FILTERS', payload: FilterState['activeFilters'] } | { type: 'SET_EXPANDED_GROUP', payload: FilterState['expandedGroup']; } function filterReducer(state: FilterState, action: FilterAction): FilterState { switch (action.type) { case 'SET_FILTER': { + const filter = action.payload; + const existingIndex = state.activeFilters.findIndex((f) => f.field === filter.field); + const activeFilters = [...state.activeFilters]; + if (existingIndex > -1) { + if (filter.value) { + activeFilters[existingIndex] = filter; + } else { + activeFilters.splice(existingIndex, 1); + } + } else if (filter.value) { + activeFilters.push(filter); + } return { ...state, - activeFilters: { ...state.activeFilters, [action.payload.field]: action.payload.value } + activeFilters } + // return { + // ...state, + // activeFilters: { ...state.activeFilters, [action.payload.field]: action.payload.value } + // } } case 'SET_ACTIVE_FILTERS': { return { @@ -49,7 +72,7 @@ interface FilterContextProps extends PropsWithChildren { } export const FilterContext: React.FC = ({ - activeFilters = {}, + activeFilters = [], onChange = (filters) => null, children }) => { @@ -61,7 +84,7 @@ export const FilterContext: React.FC = ({ */ useEffect(() => { if (onChange) onChange(state.activeFilters); - }, [state.activeFilters]); + }, [JSON.stringify(state.activeFilters)]); /** * If activeFilters is changed from outside the context (e.g. filters are reset) diff --git a/strudel-components/lib/components/FilterField.tsx b/strudel-components/lib/components/FilterField.tsx index 42a9035f..9a004314 100644 --- a/strudel-components/lib/components/FilterField.tsx +++ b/strudel-components/lib/components/FilterField.tsx @@ -6,11 +6,16 @@ import { RangeSlider } from './RangeSlider'; import { DatePicker } from '@mui/x-date-pickers'; import { useFilters } from './FilterContext'; +export type FilterOperator = 'contains' | 'contains-one-of' | 'equals' | 'equals-one-of' | 'between-inclusive' | 'between-dates-inclusive'; + +export type FilterComponent = 'RangeSlider' | 'CheckboxList' | 'DateRange' | 'TextField'; + interface FilterFieldProps extends StackProps { label: string; field: string; tooltip?: string; - filterComponent: 'RangeSlider' | 'CheckboxList' | 'DateRange' | 'TextField'; + operator: FilterOperator; + filterComponent: FilterComponent; filterProps?: any; } @@ -46,13 +51,16 @@ export const FilterField: React.FC = ({ label, field, tooltip, + operator, filterComponent, filterProps, ...rest }) => { const { state, dispatch } = useFilters(); const [value, setValue] = useState>(null); - const isActive = hasValue(state.activeFilters[field]); + console.log(state.activeFilters); + const currentFilter = state.activeFilters.find((filter) => filter.field === field); + const isActive = hasValue(currentFilter?.value); /** * When a filter is canceled, reset its value to the proper @@ -60,9 +68,10 @@ export const FilterField: React.FC = ({ * In the activeFilters variable, empty filters will always be marked as null. */ const handleCancelFilter = () => { + console.log('cancel'); switch (filterComponent) { case 'CheckboxList': - setValue([]); + setValue(null); break; case 'RangeSlider': setValue([filterProps.min, filterProps.max]); @@ -77,7 +86,7 @@ export const FilterField: React.FC = ({ console.log('Unknown filter type'); } - dispatch({ type: 'SET_FILTER', payload: { field: field, value: null } }); + dispatch({ type: 'SET_FILTER', payload: { field: field, value: null, operator } }); } /** @@ -94,7 +103,7 @@ export const FilterField: React.FC = ({ dispatch({ type: 'SET_FILTER', payload: { field: field, value: values } })} + onChange={(values) => dispatch({ type: 'SET_FILTER', payload: { field: field, value: values, operator } })} {...filterProps} /> ); @@ -109,7 +118,7 @@ export const FilterField: React.FC = ({ if (values[0] === filterProps.min && values[1] === filterProps.max) { newValues = null } - dispatch({ type: 'SET_FILTER', payload: { field: field, value: newValues } }) + dispatch({ type: 'SET_FILTER', payload: { field: field, value: newValues, operator } }) }; return ( @@ -126,7 +135,7 @@ export const FilterField: React.FC = ({ ); } case 'DateRange': { - const currentDateRange = state.activeFilters[field]; + const currentDateRange = state.activeFilters.find((filter) => filter.field === filter.field)?.value; const hasValue = currentDateRange && Array.isArray(currentDateRange) && currentDateRange.length === 2; const currentMin = hasValue && Array.isArray(currentDateRange) ? currentDateRange[0] : null; const currentMax = hasValue && Array.isArray(currentDateRange) ? currentDateRange[1] : null; @@ -140,7 +149,7 @@ export const FilterField: React.FC = ({ actions: ['clear', 'today'] } }} - onChange={(value) => dispatch({ type: 'SET_FILTER', payload: { field: field, value: [value, currentMax] } })} + onChange={(value) => dispatch({ type: 'SET_FILTER', payload: { field: field, value: [value, currentMax], operator } })} /> = ({ actions: ['clear', 'today'] } }} - onChange={(value) => dispatch({ type: 'SET_FILTER', payload: { field: field, value: [currentMin, value] } })} + onChange={(value) => dispatch({ type: 'SET_FILTER', payload: { field: field, value: [currentMin, value], operator } })} /> ); @@ -161,7 +170,7 @@ export const FilterField: React.FC = ({ */ useEffect(() => { const timeout = setTimeout(() => { - dispatch({ type: 'SET_FILTER', payload: { field: field, value: value } }) + dispatch({ type: 'SET_FILTER', payload: { field: field, value: value, operator } }) }, 1000); return () => { clearTimeout(timeout); @@ -186,7 +195,7 @@ export const FilterField: React.FC = ({ */ useEffect(() => { if (isActive) { - setValue(state.activeFilters[field]); + setValue(currentFilter?.value || null); } else if (filterComponent === 'RangeSlider') { /** RangeSliders should be considered off if both values are min and max */ if (value && (value[0] !== filterProps.min || value[1] !== filterProps.max)) { @@ -195,7 +204,7 @@ export const FilterField: React.FC = ({ } else if (hasValue(value)) { handleCancelFilter(); } - },[state.activeFilters]); + },[JSON.stringify(state.activeFilters)]); return ( void; +interface FilterPanelProps extends Omit { + onChange?: (activeFilters: FilterState['activeFilters']) => void; onClose?: () => any; config?: any; header?: React.ReactNode; @@ -26,7 +26,7 @@ export const Filters: React.FC = ({ children, ...rest }) => { - const [activeFilters, setActiveFilters] = useState({}); + const [activeFilters, setActiveFilters] = useState([]); /** * Count the number of active filters in this group by using @@ -49,7 +49,7 @@ export const Filters: React.FC = ({ } const handleReset = () => { - setActiveFilters({}); + setActiveFilters([]); } useEffect(() => { @@ -63,10 +63,11 @@ export const Filters: React.FC = ({ variant="outlined" {...rest} > - + {header && ( = ({ )} {grouped && ( - + {children} )} diff --git a/strudel-components/src/App.tsx b/strudel-components/src/App.tsx index f6f65539..a9b9b857 100644 --- a/strudel-components/src/App.tsx +++ b/strudel-components/src/App.tsx @@ -14,8 +14,8 @@ function App() { {/* */} - - {/* */} + {/* */} + ) diff --git a/strudel-components/src/examples/Filters/FiltersExNoGroups.tsx b/strudel-components/src/examples/Filters/FiltersExNoGroups.tsx index 5383cd83..858af90e 100644 --- a/strudel-components/src/examples/Filters/FiltersExNoGroups.tsx +++ b/strudel-components/src/examples/Filters/FiltersExNoGroups.tsx @@ -9,6 +9,7 @@ export const FiltersExNoGroups: React.FC = () => { return ( { { { { { { =20.0.0" } }, + "../strudel-components": { + "name": "@strudel-science/components", + "version": "0.0.2", + "extraneous": true, + "devDependencies": { + "@react-docgen/cli": "^2.0.3", + "@types/node": "^20.12.7", + "@types/react": "^18.2.66", + "@types/react-dom": "^18.2.22", + "@typescript-eslint/eslint-plugin": "^7.2.0", + "@typescript-eslint/parser": "^7.2.0", + "@vitejs/plugin-react": "^4.2.1", + "eslint": "^8.57.0", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.6", + "react-docgen": "^7.0.3", + "typescript": "^5.2.2", + "vite": "^5.2.0", + "vite-plugin-dts": "^3.8.2" + }, + "peerDependencies": { + "@emotion/react": "^11.11.4", + "@emotion/styled": "^11.11.5", + "@mui/icons-material": "^5.15.15", + "@mui/material": "^5.15.15", + "@mui/x-data-grid": "^7.11.0", + "@mui/x-date-pickers": "^7.11.0", + "dayjs": "^1.11.12", + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, "node_modules/@aashutoshrathi/word-wrap": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", @@ -361,9 +393,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.1.tgz", - "integrity": "sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz", + "integrity": "sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -436,15 +468,15 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" }, "node_modules/@emotion/babel-plugin": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz", - "integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==", + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.12.0.tgz", + "integrity": "sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==", "dependencies": { "@babel/helper-module-imports": "^7.16.7", "@babel/runtime": "^7.18.3", - "@emotion/hash": "^0.9.1", - "@emotion/memoize": "^0.8.1", - "@emotion/serialize": "^1.1.2", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.2.0", "babel-plugin-macros": "^3.1.0", "convert-source-map": "^1.5.0", "escape-string-regexp": "^4.0.0", @@ -453,6 +485,11 @@ "stylis": "4.2.0" } }, + "node_modules/@emotion/babel-plugin/node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==" + }, "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", @@ -482,18 +519,23 @@ } }, "node_modules/@emotion/hash": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", - "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==" + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==" }, "node_modules/@emotion/is-prop-valid": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz", - "integrity": "sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.3.0.tgz", + "integrity": "sha512-SHetuSLvJDzuNbOdtPVbq6yMMMlLoW5Q94uDqJZqy50gcmAjxFkVqmzqSGEFq9gT2iMuIeKV1PXVWmvUhuZLlQ==", "dependencies": { - "@emotion/memoize": "^0.8.1" + "@emotion/memoize": "^0.9.0" } }, + "node_modules/@emotion/is-prop-valid/node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==" + }, "node_modules/@emotion/memoize": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", @@ -523,33 +565,38 @@ } }, "node_modules/@emotion/serialize": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.3.tgz", - "integrity": "sha512-iD4D6QVZFDhcbH0RAG1uVu1CwVLMWUkCvAqqlewO/rxf8+87yIBAlt4+AxMiiKPLs5hFc0owNk/sLLAOROw3cA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.0.tgz", + "integrity": "sha512-jACuBa9SlYajnpIVXB+XOXnfJHyckDfe6fOpORIM6yhBDlqGuExvDdZYHDQGoDf3bZXGv7tNr+LpLjJqiEQ6EA==", "dependencies": { - "@emotion/hash": "^0.9.1", - "@emotion/memoize": "^0.8.1", - "@emotion/unitless": "^0.8.1", - "@emotion/utils": "^1.2.1", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.9.0", + "@emotion/utils": "^1.4.0", "csstype": "^3.0.2" } }, + "node_modules/@emotion/serialize/node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==" + }, "node_modules/@emotion/sheet": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==" }, "node_modules/@emotion/styled": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.11.0.tgz", - "integrity": "sha512-hM5Nnvu9P3midq5aaXj4I+lnSfNi7Pmd4EWk1fOZ3pxookaQTNew6bp4JaCBYM4HVFZF9g7UjJmsUmC2JlxOng==", + "version": "11.13.0", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.13.0.tgz", + "integrity": "sha512-tkzkY7nQhW/zC4hztlwucpT8QEZ6eUzpXDRhww/Eej4tFfO0FxQYWRyg/c5CCXa4d/f174kqeXYjuQRnhzf6dA==", "dependencies": { "@babel/runtime": "^7.18.3", - "@emotion/babel-plugin": "^11.11.0", - "@emotion/is-prop-valid": "^1.2.1", - "@emotion/serialize": "^1.1.2", - "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", - "@emotion/utils": "^1.2.1" + "@emotion/babel-plugin": "^11.12.0", + "@emotion/is-prop-valid": "^1.3.0", + "@emotion/serialize": "^1.3.0", + "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", + "@emotion/utils": "^1.4.0" }, "peerDependencies": { "@emotion/react": "^11.0.0-rc.0", @@ -562,22 +609,22 @@ } }, "node_modules/@emotion/unitless": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", - "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.9.0.tgz", + "integrity": "sha512-TP6GgNZtmtFaFcsOgExdnfxLLpRDla4Q66tnenA9CktvVSdNKDvMVuUah4QvWPIpNjrWsGg3qeGo9a43QooGZQ==" }, "node_modules/@emotion/use-insertion-effect-with-fallbacks": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz", - "integrity": "sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz", + "integrity": "sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw==", "peerDependencies": { "react": ">=16.8.0" } }, "node_modules/@emotion/utils": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz", - "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==" + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.0.tgz", + "integrity": "sha512-spEnrA1b6hDR/C68lC2M7m6ALPUHZC0lIY7jAS/B/9DuuO1ZP04eov8SMv/6fwRd8pzmsn2AuJEznRREWlQrlQ==" }, "node_modules/@emotion/weak-memoize": { "version": "0.3.1", @@ -1269,18 +1316,18 @@ } }, "node_modules/@mui/core-downloads-tracker": { - "version": "5.15.14", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.15.14.tgz", - "integrity": "sha512-on75VMd0XqZfaQW+9pGjSNiqW+ghc5E2ZSLRBXwcXl/C4YzjfyjrLPhrEpKnR9Uym9KXBvxrhoHfPcczYHweyA==", + "version": "5.16.6", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.6.tgz", + "integrity": "sha512-kytg6LheUG42V8H/o/Ptz3olSO5kUXW9zF0ox18VnblX6bO2yif1FPItgc3ey1t5ansb1+gbe7SatntqusQupg==", "funding": { "type": "opencollective", "url": "https://opencollective.com/mui-org" } }, "node_modules/@mui/icons-material": { - "version": "5.15.14", - "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.15.14.tgz", - "integrity": "sha512-vj/51k7MdFmt+XVw94sl30SCvGx6+wJLsNYjZRgxhS6y3UtnWnypMOsm3Kmg8TN+P0dqwsjy4/fX7B1HufJIhw==", + "version": "5.16.6", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.16.6.tgz", + "integrity": "sha512-ceNGjoXheH9wbIFa1JHmSc9QVjJUvh18KvHrR4/FkJCSi9HXJ+9ee1kUhCOEFfuxNF8UB6WWVrIUOUgRd70t0A==", "dependencies": { "@babel/runtime": "^7.23.9" }, @@ -1343,21 +1390,21 @@ } }, "node_modules/@mui/material": { - "version": "5.15.14", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.15.14.tgz", - "integrity": "sha512-kEbRw6fASdQ1SQ7LVdWR5OlWV3y7Y54ZxkLzd6LV5tmz+NpO3MJKZXSfgR0LHMP7meKsPiMm4AuzV0pXDpk/BQ==", + "version": "5.16.6", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.16.6.tgz", + "integrity": "sha512-0LUIKBOIjiFfzzFNxXZBRAyr9UQfmTAFzbt6ziOU2FDXhorNN2o3N9/32mNJbCA8zJo2FqFU6d3dtoqUDyIEfA==", "dependencies": { "@babel/runtime": "^7.23.9", - "@mui/base": "5.0.0-beta.40", - "@mui/core-downloads-tracker": "^5.15.14", - "@mui/system": "^5.15.14", - "@mui/types": "^7.2.14", - "@mui/utils": "^5.15.14", + "@mui/core-downloads-tracker": "^5.16.6", + "@mui/system": "^5.16.6", + "@mui/types": "^7.2.15", + "@mui/utils": "^5.16.6", + "@popperjs/core": "^2.11.8", "@types/react-transition-group": "^4.4.10", "clsx": "^2.1.0", "csstype": "^3.1.3", "prop-types": "^15.8.1", - "react-is": "^18.2.0", + "react-is": "^18.3.1", "react-transition-group": "^4.4.5" }, "engines": { @@ -1387,12 +1434,12 @@ } }, "node_modules/@mui/private-theming": { - "version": "5.15.14", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.15.14.tgz", - "integrity": "sha512-UH0EiZckOWcxiXLX3Jbb0K7rC8mxTr9L9l6QhOZxYc4r8FHUkefltV9VDGLrzCaWh30SQiJvAEd7djX3XXY6Xw==", + "version": "5.16.6", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.16.6.tgz", + "integrity": "sha512-rAk+Rh8Clg7Cd7shZhyt2HGTTE5wYKNSJ5sspf28Fqm/PZ69Er9o6KX25g03/FG2dfpg5GCwZh/xOojiTfm3hw==", "dependencies": { "@babel/runtime": "^7.23.9", - "@mui/utils": "^5.15.14", + "@mui/utils": "^5.16.6", "prop-types": "^15.8.1" }, "engines": { @@ -1413,9 +1460,9 @@ } }, "node_modules/@mui/styled-engine": { - "version": "5.15.14", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.15.14.tgz", - "integrity": "sha512-RILkuVD8gY6PvjZjqnWhz8fu68dVkqhM5+jYWfB5yhlSQKg+2rHkmEwm75XIeAqI3qwOndK6zELK5H6Zxn4NHw==", + "version": "5.16.6", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.16.6.tgz", + "integrity": "sha512-zaThmS67ZmtHSWToTiHslbI8jwrmITcN93LQaR2lKArbvS7Z3iLkwRoiikNWutx9MBs8Q6okKvbZq1RQYB3v7g==", "dependencies": { "@babel/runtime": "^7.23.9", "@emotion/cache": "^11.11.0", @@ -1444,15 +1491,15 @@ } }, "node_modules/@mui/system": { - "version": "5.15.14", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.15.14.tgz", - "integrity": "sha512-auXLXzUaCSSOLqJXmsAaq7P96VPRXg2Rrz6OHNV7lr+kB8lobUF+/N84Vd9C4G/wvCXYPs5TYuuGBRhcGbiBGg==", + "version": "5.16.6", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.16.6.tgz", + "integrity": "sha512-5xgyJjBIMPw8HIaZpfbGAaFYPwImQn7Nyh+wwKWhvkoIeDosQ1ZMVrbTclefi7G8hNmqhip04duYwYpbBFnBgw==", "dependencies": { "@babel/runtime": "^7.23.9", - "@mui/private-theming": "^5.15.14", - "@mui/styled-engine": "^5.15.14", - "@mui/types": "^7.2.14", - "@mui/utils": "^5.15.14", + "@mui/private-theming": "^5.16.6", + "@mui/styled-engine": "^5.16.6", + "@mui/types": "^7.2.15", + "@mui/utils": "^5.16.6", "clsx": "^2.1.0", "csstype": "^3.1.3", "prop-types": "^15.8.1" @@ -1483,9 +1530,9 @@ } }, "node_modules/@mui/types": { - "version": "7.2.14", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.14.tgz", - "integrity": "sha512-MZsBZ4q4HfzBsywtXgM1Ksj6HDThtiwmOKUXH1pKYISI9gAVXCNHNpo7TlGoGrBaYWZTdNoirIN7JsQcQUjmQQ==", + "version": "7.2.15", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.15.tgz", + "integrity": "sha512-nbo7yPhtKJkdf9kcVOF8JZHPZTmqXjJ/tI0bdWgHg5tp9AnIN4Y7f7wm9T+0SyGYJk76+GYZ8Q5XaTYAsUHN0Q==", "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0" }, @@ -1496,14 +1543,16 @@ } }, "node_modules/@mui/utils": { - "version": "5.15.14", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.15.14.tgz", - "integrity": "sha512-0lF/7Hh/ezDv5X7Pry6enMsbYyGKjADzvHyo3Qrc/SSlTsQ1VkbDMbH0m2t3OR5iIVLwMoxwM7yGd+6FCMtTFA==", + "version": "5.16.6", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.16.6.tgz", + "integrity": "sha512-tWiQqlhxAt3KENNiSRL+DIn9H5xNVK6Jjf70x3PnfQPz1MPBdh7yyIcAyVBT9xiw7hP3SomRhPR7hzBMBCjqEA==", "dependencies": { "@babel/runtime": "^7.23.9", - "@types/prop-types": "^15.7.11", + "@mui/types": "^7.2.15", + "@types/prop-types": "^15.7.12", + "clsx": "^2.1.1", "prop-types": "^15.8.1", - "react-is": "^18.2.0" + "react-is": "^18.3.1" }, "engines": { "node": ">=12.0.0" @@ -1523,14 +1572,15 @@ } }, "node_modules/@mui/x-data-grid": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-7.0.0.tgz", - "integrity": "sha512-Nwwfr+ot/di0oH/pVwIxKV2QD7QyUY/MKkTWRSKzQoJw2aiFQf1Usmvq9Fu1qsCsvMmqIFaToY7972p0cczRjw==", - "dependencies": { - "@babel/runtime": "^7.24.0", - "@mui/system": "^5.15.14", - "@mui/utils": "^5.15.14", - "clsx": "^2.1.0", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-7.12.0.tgz", + "integrity": "sha512-5cS/v0PFMfm2na6iC77eeM/63m+gu4YYQcFycvGY6i5qm6ZywHzdcyXxx13FENKPclY1p9i19f4t4iuYW2F9Eg==", + "dependencies": { + "@babel/runtime": "^7.25.0", + "@mui/system": "^5.16.5", + "@mui/utils": "^5.16.5", + "@mui/x-internals": "7.12.0", + "clsx": "^2.1.1", "prop-types": "^15.8.1", "reselect": "^4.1.8" }, @@ -1548,16 +1598,15 @@ } }, "node_modules/@mui/x-date-pickers": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-7.0.0.tgz", - "integrity": "sha512-/9mp4O2WMixHOso63DBoZVfJVYGrzOHF5voheV2tYQ4XqDdTKp2AdWS3oh8PGwrsvCzqkvb3quzTqhKoEsJUwA==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-7.12.0.tgz", + "integrity": "sha512-WU5C7QNfSpJ9cP8vl2sY7q35NW+0TUMgEy+sl98fcPhLckq3cgV1wnVxoZnQZ3BxVQAtx+7ag/MpefU03vJcVw==", "dependencies": { - "@babel/runtime": "^7.24.0", - "@mui/base": "^5.0.0-beta.40", - "@mui/system": "^5.15.14", - "@mui/utils": "^5.15.14", + "@babel/runtime": "^7.25.0", + "@mui/system": "^5.16.5", + "@mui/utils": "^5.16.5", "@types/react-transition-group": "^4.4.10", - "clsx": "^2.1.0", + "clsx": "^2.1.1", "prop-types": "^15.8.1", "react-transition-group": "^4.4.5" }, @@ -1573,7 +1622,7 @@ "@emotion/styled": "^11.8.1", "@mui/material": "^5.15.14", "date-fns": "^2.25.0 || ^3.2.0", - "date-fns-jalali": "^2.13.0-0", + "date-fns-jalali": "^2.13.0-0 || ^3.2.0-0", "dayjs": "^1.10.7", "luxon": "^3.0.2", "moment": "^2.29.4", @@ -1612,6 +1661,25 @@ } } }, + "node_modules/@mui/x-internals": { + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-7.12.0.tgz", + "integrity": "sha512-zgu/JqSXBflSvtzfFN8lNi5Wxw79czBv6V/crOrXqCCOzxAIsrcup2FZlwvXlzetm3otS7o/Tzfo/O5dE68NkA==", + "dependencies": { + "@babel/runtime": "^7.25.0", + "@mui/utils": "^5.16.5" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2618,9 +2686,9 @@ "integrity": "sha512-kgMuFyE78OC6Dyu3Dy7vcx4uy97EIbVxJB/B0eJ3bUNAkwdNcxYzgKltnyADiYwsR7SEqkkUPsEUT//OVS6XMA==" }, "node_modules/clsx": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", - "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", "engines": { "node": ">=6" } @@ -3012,9 +3080,9 @@ "integrity": "sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw==" }, "node_modules/dayjs": { - "version": "1.11.10", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", - "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" + "version": "1.11.12", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.12.tgz", + "integrity": "sha512-Rt2g+nTbLlDWZTwwrIXjy9MeiZmSDI375FvZs72ngxx8PDC6YXOeR3q5LAuPzjZQxhiWdRKac7RKV+YyQYfYIg==" }, "node_modules/debug": { "version": "4.3.4", @@ -5507,9 +5575,9 @@ } }, "node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==" }, "node_modules/react-plotly.js": { "version": "2.6.0", diff --git a/strudel-taskflows/src/pages/explore-data/_components/FiltersPanel.tsx b/strudel-taskflows/src/pages/explore-data/_components/FiltersPanel.tsx index c7209baf..27ac1dc0 100644 --- a/strudel-taskflows/src/pages/explore-data/_components/FiltersPanel.tsx +++ b/strudel-taskflows/src/pages/explore-data/_components/FiltersPanel.tsx @@ -1,14 +1,14 @@ -import { Stack } from '@mui/material'; +import { Box, Stack } from '@mui/material'; import { DatePicker } from '@mui/x-date-pickers'; import React from 'react'; import { CheckboxList } from '../../../components/CheckboxList'; -import { FilterField } from '../../../components/FilterField'; -import { Filters } from '../../../components/Filters'; import { StrudelSlider } from '../../../components/StrudelSlider'; -import { FilterConfig, FilterOperator } from '../../../types/filters.types'; +import { DataFilter, FilterConfig, FilterOperator } from '../../../types/filters.types'; import { useExploreData } from '../_context/ContextProvider'; -import { setFilter } from '../_context/actions'; +import { setActiveFilters, setFilter } from '../_context/actions'; import { taskflow } from '../_config/taskflow.config'; +import { FilterField, Filters } from '@strudel-science/components'; +import { FilterState } from '@strudel-science/components/dist/components/FilterContext'; interface FiltersPanelProps { onClose: () => any @@ -22,60 +22,8 @@ interface FiltersPanelProps { export const FiltersPanel: React.FC = (props) => { const {state, dispatch} = useExploreData(); - /** - * Render filter component based on the `filterType` from the filter definition. - */ - const getFilterComponent = (filter: FilterConfig) => { - switch (filter.filterType) { - case 'CheckboxList': { - return ( - dispatch(setFilter({ field: filter.field, value: values, operator: FilterOperator.CONTAINS_ONE_OF }))} - /> - ); - } - case 'Slider': { - return ( - filter.field} - valueLabelDisplay="auto" - min={filter.props.min} - max={filter.props.max} - onChangeCommitted={(event, values) => dispatch(setFilter({ field: filter.field, value: values, operator: FilterOperator.BETWEEN_INCLUSIVE }))} - /> - ); - } - case 'date range': { - const currentDateRange = state.activeFilters.find((filter) => filter.field === filter.field); - const hasValue = currentDateRange && Array.isArray(currentDateRange.value) && currentDateRange.value.length === 2; - const currentMin = hasValue && Array.isArray(currentDateRange.value) ? currentDateRange.value[0] : null; - const currentMax = hasValue && Array.isArray(currentDateRange.value) ? currentDateRange.value[1] : null; - - return ( - - dispatch(setFilter({ field: filter.field, value: [value, currentMax], operator: FilterOperator.BETWEEN_DATES_INCLUSIVE }))} - /> - dispatch(setFilter({ field: filter.field, value: [currentMin, value], operator: FilterOperator.BETWEEN_DATES_INCLUSIVE }))} - /> - - ); - } - } + const handleFiltersChange = (filters: FilterState["activeFilters"]) => { + dispatch(setActiveFilters(filters as DataFilter[])); } /** @@ -83,20 +31,18 @@ export const FiltersPanel: React.FC = (props) => { */ return ( {taskflow.pages.index.tableFilters.map((f, i) => ( ))} diff --git a/strudel-taskflows/src/pages/explore-data/_config/taskflow.config.ts b/strudel-taskflows/src/pages/explore-data/_config/taskflow.config.ts index 313e090b..e9515486 100644 --- a/strudel-taskflows/src/pages/explore-data/_config/taskflow.config.ts +++ b/strudel-taskflows/src/pages/explore-data/_config/taskflow.config.ts @@ -73,16 +73,21 @@ export const taskflow: ExploreDataConfig = { /** * Text to display in the label for the filter. */ - displayName: "Assembly", + label: "Assembly", + /** + * Type of filtering operation to use. + * Must be 'contains' | 'contains-one-of' | 'equals' | 'equals-one-of' | 'between-inclusive' | 'between-dates-inclusive' + */ + operator: "contains-one-of", /** * The kind of filter component and function to use. * Must be "CheckboxList", "Slider", or "date range". */ - filterType: "CheckboxList", + filterComponent: "CheckboxList", /** * Extra options to pass to the filter based on the filter type. */ - props: { + filterProps: { options: [ { label: "JGI", @@ -101,9 +106,10 @@ export const taskflow: ExploreDataConfig = { }, { field: "Data Usage Policy", - displayName: "Data Usage Policy", - filterType: "CheckboxList", - props: { + label: "Data Usage Policy", + operator: "contains-one-of", + filterComponent: "CheckboxList", + filterProps: { options: [ { label: "restricted", @@ -118,18 +124,20 @@ export const taskflow: ExploreDataConfig = { }, { field: "Euk. BUSCO %", - displayName: "Euk. BUSCO %", - filterType: "Slider", - props: { + label: "Euk. BUSCO %", + operator: "between-inclusive", + filterComponent: "RangeSlider", + filterProps: { min: 0, max: 100 } }, { field: "Emb. BUSCO %", - displayName: "Emb. BUSCO %", - filterType: "Slider", - props: { + label: "Emb. BUSCO %", + operator: "between-inclusive", + filterComponent: "RangeSlider", + filterProps: { min: 0, max: 100 } diff --git a/strudel-taskflows/src/pages/explore-data/_config/taskflow.types.ts b/strudel-taskflows/src/pages/explore-data/_config/taskflow.types.ts index a8a22e23..570d7f7d 100644 --- a/strudel-taskflows/src/pages/explore-data/_config/taskflow.types.ts +++ b/strudel-taskflows/src/pages/explore-data/_config/taskflow.types.ts @@ -1,4 +1,5 @@ import { GridColDef } from "@mui/x-data-grid" +import { FilterComponent, FilterOperator } from "@strudel-science/components/dist/components/FilterField" /** * Type definitions for the Compare Data Task Flow config object @@ -24,9 +25,10 @@ export interface ExploreDataConfig { tableColumns: GridColDef[], tableFilters: { field: string, - displayName: string, - filterType: 'CheckboxList' | 'Slider' | 'date range', - props?: object + label: string, + operator: FilterOperator + filterComponent: FilterComponent, + filterProps?: object }[] } } diff --git a/strudel-taskflows/src/pages/explore-data/_context/ContextProvider.tsx b/strudel-taskflows/src/pages/explore-data/_context/ContextProvider.tsx index a8a978ec..d28f8b5a 100644 --- a/strudel-taskflows/src/pages/explore-data/_context/ContextProvider.tsx +++ b/strudel-taskflows/src/pages/explore-data/_context/ContextProvider.tsx @@ -98,6 +98,12 @@ function exploreDataReducer(state: ExploreDataState, action: ExploreDataAction): activeFilters } } + case ExploreDataActionType.SET_ACTIVE_FILTERS: { + return { + ...state, + activeFilters: action.payload + } + } case ExploreDataActionType.SET_PREVIEW_ITEM: { return { ...state, diff --git a/strudel-taskflows/src/pages/explore-data/_context/actions.ts b/strudel-taskflows/src/pages/explore-data/_context/actions.ts index 6ebcd477..d7e3f381 100644 --- a/strudel-taskflows/src/pages/explore-data/_context/actions.ts +++ b/strudel-taskflows/src/pages/explore-data/_context/actions.ts @@ -6,6 +6,7 @@ export enum ExploreDataActionType { SET_SEARCH = 'SET_SEARCH', SET_FILTERED_DATA = 'SET_FILTERED_DATA', SET_FILTER = 'SET_FILTER', + SET_ACTIVE_FILTERS = 'SET_ACTIVE_FILTERS', SET_PREVIEW_ITEM = 'SET_PREVIEW_ITEM' } @@ -34,6 +35,11 @@ export const setFilter = (filter: DataFilter): ExploreDataAction => ({ payload: filter, }); +export const setActiveFilters = (activeFilters: ExploreDataState['activeFilters']): ExploreDataAction => ({ + type: ExploreDataActionType.SET_ACTIVE_FILTERS, + payload: activeFilters, +}); + export const setPreviewItem = (rowItem: ExploreDataState['previewItem']): ExploreDataAction => ({ type: ExploreDataActionType.SET_PREVIEW_ITEM, payload: rowItem, diff --git a/strudel-taskflows/src/pages/index.tsx b/strudel-taskflows/src/pages/index.tsx index 92cc3ed6..ba56ad2c 100644 --- a/strudel-taskflows/src/pages/index.tsx +++ b/strudel-taskflows/src/pages/index.tsx @@ -40,9 +40,9 @@ const HomePage: React.FC = () => { }} > You just built an app with STRUDEL! - + Get started by going to /playground and editing src/pages/playground/index.tsx} /> - + diff --git a/strudel-taskflows/src/utils/filters.utils.ts b/strudel-taskflows/src/utils/filters.utils.ts index 7f7b55d1..76432090 100644 --- a/strudel-taskflows/src/utils/filters.utils.ts +++ b/strudel-taskflows/src/utils/filters.utils.ts @@ -24,13 +24,13 @@ export const filterByDataFilters = (allData: any[], filters: DataFilter[]) => { let match = false; if (include === true) { switch (f.operator) { - case FilterOperator.CONTAINS: { + case 'contains': { if (d[f.field].indexOf(f.value) > -1) { match = true; } break; } - case FilterOperator.CONTAINS_ONE_OF: { + case 'contains-one-of': { if (Array.isArray(f.value)) { f.value.forEach((v) => { if (!match) { @@ -49,7 +49,7 @@ export const filterByDataFilters = (allData: any[], filters: DataFilter[]) => { } break; } - case FilterOperator.EQUALS_ONE_OF: { + case 'equals-one-of': { console.log(f.value); console.log(d[f.field]); if (Array.isArray(f.value)) { @@ -63,7 +63,7 @@ export const filterByDataFilters = (allData: any[], filters: DataFilter[]) => { } break; } - case FilterOperator.BETWEEN_INCLUSIVE: { + case 'between-inclusive': { if (Array.isArray(f.value)) { const min = f.value[0]; const max = f.value[1]; @@ -73,7 +73,7 @@ export const filterByDataFilters = (allData: any[], filters: DataFilter[]) => { } break; } - case FilterOperator.BETWEEN_DATES_INCLUSIVE: { + case 'between-dates-inclusive': { if ( typeof d[f.field] === 'string' && Array.isArray(f.value) From 4af854102c6d3cfc17c780a48917c4b5597b11e5 Mon Sep 17 00:00:00 2001 From: Cody O'Donnell Date: Thu, 15 Aug 2024 13:41:44 -0700 Subject: [PATCH 4/5] Export types from library --- strudel-components/lib/main.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/strudel-components/lib/main.tsx b/strudel-components/lib/main.tsx index d3a643e5..679f7562 100644 --- a/strudel-components/lib/main.tsx +++ b/strudel-components/lib/main.tsx @@ -4,6 +4,8 @@ export { Filters } from './components/Filters' export { FilterField } from './components/FilterField' export { FilterGroup } from './components/FilterGroup' export { FilterContext } from './components/FilterContext' +export type { DataFilter } from './components/FilterContext' +export type { FilterOperator, FilterComponent } from './components/FilterField' export { SciDataGrid } from './components/SciDataGrid' export type { SciDataGridColDef } from './components/SciDataGrid' export { Formula } from './components/Formula' From 6391321348f45e8066f21fcc3057174505ad41d1 Mon Sep 17 00:00:00 2001 From: Cody O'Donnell Date: Fri, 16 Aug 2024 13:09:14 -0700 Subject: [PATCH 5/5] Add SciDataGrid and Filters components to explore-data task flow --- .../lib/components/SciDataGrid.tsx | 36 ++++++++++----- strudel-components/package-lock.json | 45 +++++-------------- strudel-components/package.json | 10 ++--- strudel-components/src/App.tsx | 4 +- .../_components/DataTablePanel.tsx | 9 ++-- .../explore-data/_components/FiltersPanel.tsx | 3 ++ .../explore-data/_config/taskflow.config.ts | 3 ++ .../explore-data/_config/taskflow.types.ts | 4 +- 8 files changed, 58 insertions(+), 56 deletions(-) diff --git a/strudel-components/lib/components/SciDataGrid.tsx b/strudel-components/lib/components/SciDataGrid.tsx index 284fc3a0..5b07c28a 100644 --- a/strudel-components/lib/components/SciDataGrid.tsx +++ b/strudel-components/lib/components/SciDataGrid.tsx @@ -1,4 +1,4 @@ -import { Stack, Typography } from '@mui/material'; +import { Box, Typography } from '@mui/material'; import { DataGrid, DataGridProps, GridColDef, GridColumnHeaderParams, GridRenderCellParams } from '@mui/x-data-grid'; import React, { ReactNode } from 'react'; import { ArrayWithPopover } from './ArrayWithPopover'; @@ -40,15 +40,31 @@ const getGridColumns = (columns: SciDataGridColDef[]) => { ...gridColumn } = column; - /** Render unit label underneath the headerName */ - if (units) { - gridColumn.renderHeader = (params: GridColumnHeaderParams) => ( - - {params.colDef.headerName} - {units} - - ) - } + /** + * Style column header and render unit label + * underneath the headerName if units supplied + */ + gridColumn.renderHeader = (params: GridColumnHeaderParams) => ( + + {params.colDef.headerName} + {units && ( + + {units} + + )} + + ) /** Handle value transformation options */ if (!gridColumn.valueFormatter) { diff --git a/strudel-components/package-lock.json b/strudel-components/package-lock.json index 8fcddcda..911eab5a 100644 --- a/strudel-components/package-lock.json +++ b/strudel-components/package-lock.json @@ -25,11 +25,11 @@ }, "peerDependencies": { "@emotion/react": "^11.11.4", - "@emotion/styled": "^11.11.5", - "@mui/icons-material": "^5.15.15", - "@mui/material": "^5.15.15", - "@mui/x-data-grid": "^7.11.0", - "@mui/x-date-pickers": "^7.11.0", + "@emotion/styled": "^11.11.0", + "@mui/icons-material": "^5.15.14", + "@mui/material": "^5.15.14", + "@mui/x-data-grid": "^7.0.0", + "@mui/x-date-pickers": "^7.0.0", "dayjs": "^1.11.12", "react": "^18.0.0", "react-dom": "^18.0.0" @@ -1574,16 +1574,15 @@ } }, "node_modules/@mui/x-data-grid": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-7.11.0.tgz", - "integrity": "sha512-dXaIw3Noxc4d6xenS7J+zMPORG9ptkTW7B81P6QFovILSEuI/qebQhijy/IkqRvcCsuZYLL3nA89bp+EDI503Q==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-7.0.0.tgz", + "integrity": "sha512-Nwwfr+ot/di0oH/pVwIxKV2QD7QyUY/MKkTWRSKzQoJw2aiFQf1Usmvq9Fu1qsCsvMmqIFaToY7972p0cczRjw==", "peer": true, "dependencies": { - "@babel/runtime": "^7.24.8", - "@mui/system": "^5.16.2", - "@mui/utils": "^5.16.2", - "@mui/x-internals": "7.11.0", - "clsx": "^2.1.1", + "@babel/runtime": "^7.24.0", + "@mui/system": "^5.15.14", + "@mui/utils": "^5.15.14", + "clsx": "^2.1.0", "prop-types": "^15.8.1", "reselect": "^4.1.8" }, @@ -1666,26 +1665,6 @@ } } }, - "node_modules/@mui/x-internals": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-7.11.0.tgz", - "integrity": "sha512-GqCYylKiB4cLH9tK4JweJlT2JvPjnpXjS3TEIqtHB4BcSsezhdRrMGzHOO5zCJqkasqTirJh2t6X16Qw1llr4Q==", - "peer": true, - "dependencies": { - "@babel/runtime": "^7.24.8", - "@mui/utils": "^5.16.2" - }, - "engines": { - "node": ">=14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "react": "^17.0.0 || ^18.0.0" - } - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", diff --git a/strudel-components/package.json b/strudel-components/package.json index c18b7194..86b5eb85 100644 --- a/strudel-components/package.json +++ b/strudel-components/package.json @@ -38,11 +38,11 @@ }, "peerDependencies": { "@emotion/react": "^11.11.4", - "@emotion/styled": "^11.11.5", - "@mui/icons-material": "^5.15.15", - "@mui/material": "^5.15.15", - "@mui/x-data-grid": "^7.11.0", - "@mui/x-date-pickers": "^7.11.0", + "@emotion/styled": "^11.11.0", + "@mui/icons-material": "^5.15.14", + "@mui/material": "^5.15.14", + "@mui/x-data-grid": "^7.0.0", + "@mui/x-date-pickers": "^7.0.0", "dayjs": "^1.11.12", "react": "^18.0.0", "react-dom": "^18.0.0" diff --git a/strudel-components/src/App.tsx b/strudel-components/src/App.tsx index a9b9b857..0bfb89e2 100644 --- a/strudel-components/src/App.tsx +++ b/strudel-components/src/App.tsx @@ -13,9 +13,9 @@ function App() { - {/* */} + {/* */} - + {/* */} ) diff --git a/strudel-taskflows/src/pages/explore-data/_components/DataTablePanel.tsx b/strudel-taskflows/src/pages/explore-data/_components/DataTablePanel.tsx index 8453cb59..d7efd29a 100644 --- a/strudel-taskflows/src/pages/explore-data/_components/DataTablePanel.tsx +++ b/strudel-taskflows/src/pages/explore-data/_components/DataTablePanel.tsx @@ -1,8 +1,8 @@ import FilterListIcon from '@mui/icons-material/FilterList'; import { Button, Paper, Stack, TextField, Typography } from '@mui/material'; import { GridEventListener } from '@mui/x-data-grid'; +import { SciDataGrid } from '@strudel-science/components'; import React from 'react'; -import { DataGrid } from '@mui/x-data-grid'; import { useExploreData } from '../_context/ContextProvider'; import { setPreviewItem, setSearch } from '../_context/actions'; @@ -18,7 +18,7 @@ interface DataTablePanelProps { export const DataTablePanel: React.FC = (props) => { const {state, dispatch} = useExploreData(); - const handleRowClick: GridEventListener<'rowClick'> = (rowData) => { + const handleRowClick: GridEventListener<"rowClick"> = (rowData) => { dispatch(setPreviewItem(rowData.row)); }; @@ -53,9 +53,9 @@ export const DataTablePanel: React.FC = (props) => { onChange={handleSearch} /> - row[state.dataIdField]} + getRowId={(row: any) => row[state.dataIdField]} columns={state.columns} disableColumnSelector initialState={{ @@ -64,6 +64,7 @@ export const DataTablePanel: React.FC = (props) => { {...props} onRowClick={handleRowClick} sx={{ + border: 'none', '& .MuiDataGrid-cell:focus-within': { outline: 'none' }, diff --git a/strudel-taskflows/src/pages/explore-data/_components/FiltersPanel.tsx b/strudel-taskflows/src/pages/explore-data/_components/FiltersPanel.tsx index 27ac1dc0..7f0895f1 100644 --- a/strudel-taskflows/src/pages/explore-data/_components/FiltersPanel.tsx +++ b/strudel-taskflows/src/pages/explore-data/_components/FiltersPanel.tsx @@ -34,6 +34,9 @@ export const FiltersPanel: React.FC = (props) => { grouped={false} onClose={props.onClose} onChange={handleFiltersChange} + sx={{ + border: 'none' + }} > {taskflow.pages.index.tableFilters.map((f, i) => (