From beab5a4a3baf16632f9829dce0b3e6e151db49ff Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 7 Jul 2025 20:08:34 +0000 Subject: [PATCH] feat: Add ability to hide columns in ResultsView Implemented a feature allowing users to hide specific columns in the query results view. - Settings for hidden columns are stored as a child block named `hiddenColumns` under the `results` block. - Updated `parseResultSettings` to read and return `hiddenColumns`. - Modified `ResultsView` to include UI for selecting columns to hide (via a MultiSelect in the 'More' menu) and logic to filter out hidden columns from display. - Added `hiddenColumns` to the `ParsedResultSettings` type definition. - Ensured that other functionalities like sorting, filtering, and different layouts respect the hidden columns. --- src/components/ResultsView.tsx | 71 +++++++++++++++++++++++++++----- src/utils/parseResultSettings.ts | 11 +++-- src/utils/types.ts | 27 ++++++++++++ 3 files changed, 96 insertions(+), 13 deletions(-) diff --git a/src/components/ResultsView.tsx b/src/components/ResultsView.tsx index 098f6d01..ac3c3b3e 100644 --- a/src/components/ResultsView.tsx +++ b/src/components/ResultsView.tsx @@ -314,6 +314,7 @@ const ResultsView: ResultsViewComponent = ({ const [columnFilters, setColumnFilters] = useState(settings.columnFilters); const [searchFilter, setSearchFilter] = useState(settings.searchFilter); const [showInterface, setShowInterface] = useState(settings.showInterface); + const [hiddenColumns, setHiddenColumns] = useState(settings.hiddenColumns); const [showMenuIcons, setShowMenuIcons] = useState(false); const { allProcessedResults, paginatedResults } = useMemo(() => { @@ -360,6 +361,7 @@ const ResultsView: ResultsViewComponent = ({ const [isEditColumnSort, setIsEditColumnSort] = useState(false); const [isEditColumnFilter, setIsEditColumnFilter] = useState(false); const [isEditSearchFilter, setIsEditSearchFilter] = useState(false); + const [isEditHiddenColumns, setIsEditHiddenColumns] = useState(false); const [layout, setLayout] = useState(settings.layout); const layoutMode = useMemo( @@ -370,9 +372,10 @@ const ResultsView: ResultsViewComponent = ({ () => searchFilter || columnFilters.length || + hiddenColumns.length || random.count || (activeSort.length && layout.mode !== "table"), // indicator is on ResultHeader - [searchFilter, columnFilters, random, activeSort, layout.mode] + [searchFilter, columnFilters, hiddenColumns, random, activeSort, layout.mode] ); const onViewChange = (view: (typeof views)[number], i: number) => { const newViews = views.map((v, j) => (i === j ? view : v)); @@ -405,6 +408,11 @@ const ResultsView: ResultsViewComponent = ({ (view) => VIEWS[view.mode]?.value === true ); + const visibleColumns = useMemo( + () => columns.filter((c) => !hiddenColumns.includes(c.key)), + [columns, hiddenColumns] + ); + return (
{ const options = s.options === "columns" - ? columns.map((c) => c.key) + ? visibleColumns.map((c) => c.key) : s.options.slice(); return (
))} c.key) .filter((c) => !activeSort.some((as) => as.key === c))} transformItem={(k) => @@ -663,7 +672,7 @@ const ResultsView: ResultsViewComponent = ({ ButtonProps={{ text: "Choose Column", intent: "primary", - disabled: columns.length === activeSort.length, + disabled: visibleColumns.length === activeSort.length, }} onItemSelect={(column) => { resultViewSetActiveSort([ @@ -689,7 +698,7 @@ const ResultsView: ResultsViewComponent = ({
c.key)} + items={visibleColumns.map((c) => c.key)} transformItem={(k) => k.length > 10 ? `${k.slice(0, 7)}...` : k } @@ -825,7 +834,7 @@ const ResultsView: ResultsViewComponent = ({ intent="primary" onClick={() => { const newFilter = { - key: columns[0].key, + key: visibleColumns[0].key, type: SUPPORTED_COLUMN_FILTER_TYPES[0].id, value: [""], uid: window.roamAlphaAPI.util.generateUID(), @@ -942,6 +951,40 @@ const ResultsView: ResultsViewComponent = ({
+ ) : isEditHiddenColumns ? ( +
+ setIsEditHiddenColumns(false)} + text="Hide Columns" + /> + c.key)} + selectedItems={hiddenColumns} + itemRenderer={(item, { handleClick, modifiers }) => ( + + )} + onItemSelect={(item) => { + const newHiddenColumns = hiddenColumns.includes(item) + ? hiddenColumns.filter((hc) => hc !== item) + : [...hiddenColumns, item]; + setHiddenColumns(newHiddenColumns); + if (preventSavingSettings) return; + setInputSettings({ + key: "hiddenColumns", + values: newHiddenColumns, + blockUid: settings.resultNodeUid, + }); + }} + tagRenderer={(item) => item} + popoverProps={{ minimal: true }} + /> +
) : ( {onEdit && ( @@ -975,6 +1018,14 @@ const ResultsView: ResultsViewComponent = ({ setIsEditViews(true); }} /> + { + setIsEditHiddenColumns(true); + }} + /> ) : layoutMode === "bar" ? ( ) : layoutMode === "timeline" ? ( @@ -1167,7 +1218,7 @@ const ResultsView: ResultsViewComponent = ({ data={allProcessedResults} layout={layout} onQuery={() => onRefresh(true)} - resultKeys={columns} + resultKeys={visibleColumns} parentUid={parentUid} views={views} activeSort={activeSort} diff --git a/src/utils/parseResultSettings.ts b/src/utils/parseResultSettings.ts index f7e0a3c2..954fea0a 100644 --- a/src/utils/parseResultSettings.ts +++ b/src/utils/parseResultSettings.ts @@ -5,11 +5,11 @@ import getSettingIntFromTree from "roamjs-components/util/getSettingIntFromTree" import getSubTree from "roamjs-components/util/getSubTree"; import toFlexRegex from "roamjs-components/util/toFlexRegex"; import { StoredFilters } from "../components/DefaultFilters"; -import { Column } from "./types"; +import { Column, ParsedResultSettings } from "./types"; import getSettingValueFromTree from "roamjs-components/util/getSettingValueFromTree"; import getSettingValuesFromTree from "roamjs-components/util/getSettingValuesFromTree"; -export type Sorts = { key: string; descending: boolean }[]; +export type Sorts = ParsedResultSettings["activeSort"]; export type FilterData = Record; export type Views = { column: string; @@ -71,7 +71,7 @@ const parseResultSettings = ( parentUid: string, columns: Column[], extensionAPI?: OnloadArgs["extensionAPI"] -) => { +): ParsedResultSettings => { const { globalFiltersData, globalPageSize } = getSettings(extensionAPI); const tree = getBasicTreeByParentUid(parentUid); const resultNode = getSubTree({ tree, key: "results" }); @@ -89,6 +89,10 @@ const parseResultSettings = ( tree: resultNode.children, key: "interface", }); + const hiddenColumnsNode = getSubTree({ + tree: resultNode.children, + key: "hiddenColumns", + }); const filterEntries = getFilterEntries(filtersNode); const savedFilterData = filterEntries.length ? Object.fromEntries(filterEntries) @@ -165,6 +169,7 @@ const parseResultSettings = ( pageSize, layout, page: 1, // TODO save in roam data + hiddenColumns: hiddenColumnsNode.children.map((c) => c.text), }; }; diff --git a/src/utils/types.ts b/src/utils/types.ts index 0df3c61e..d8373b60 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -51,3 +51,30 @@ export type Column = { key: string; uid: string; selection: string }; export type QBGlobalRefs = { [key: string]: (args: Record) => void; }; + +export type ParsedResultSettings = { + resultNodeUid: string; + activeSort: { key: string; descending: boolean }[]; + searchFilter: string; + showInterface: boolean; + filters: Record< + string, + { includes: { values: Set }; excludes: { values: Set } } + >; + columnFilters: { + key: string; + uid: string; + value: string[]; + type: string; + }[]; + views: { + column: string; + mode: string; + value: string; + }[]; + random: number; + pageSize: number; + layout: Record & { uid?: string }; + page: number; + hiddenColumns: string[]; +};