Repository: h2oai/wave
File: ui/src/table.tsx (TypeScript)

Code before:
          : groupByKey !== '*'
            ? items.reduce((acc, item) => {
              const group = (item as Fluent.IObjectWithKey & Dict<any>)[groupByKey]
              if (!acc[group]) acc[group] = ({ key: group, name: group, startIndex: 0, count: 0 })
              return acc
            }, {} as Dict<Fluent.IGroup>)
            : {}
      }, [m.groups, groupByKey, items]),
      makeGroups = React.useCallback((groupByKey: S, filteredItems: (Fluent.IObjectWithKey & Dict<any>)[]) => {
        const allGroups: Dict<Fluent.IGroup> = { ...initialGroups }
        let
          groups: Fluent.IGroup[],
          groupedBy: Dict<any> = []

        if (m.groups) {
          filteredItems.forEach(({ group }, idx) => {
            allGroups[group].count === 0
              ? allGroups[group] = ({ key: group, name: group, startIndex: idx, count: 1, isCollapsed: getIsCollapsed(group, expandedRefs.current) })
              : allGroups[group].count++
          })
          groups = Object.values(allGroups)
        } else {
          let prevSum = 0
          groupedBy = groupByF(filteredItems, groupByKey)
          const
            groupedByKeys = Object.keys(groupedBy),
            groupByColType = m.columns.find(c => c.name === groupByKey)?.data_type

          groupedByKeys.forEach((key, i) => {
            if (i !== 0) {
              const prevKey = groupedByKeys[i - 1]
              prevSum += groupedBy[prevKey].length
            }
            const name = groupByColType === 'time' ? new Date(key).toLocaleString() : key
            allGroups[key] = { key, name, startIndex: prevSum, count: groupedBy[key].length, isCollapsed: getIsCollapsed(key, expandedRefs.current) }
          })

          groups = Object.values(allGroups).sort(({ name: name1 }, { name: name2 }) => {
            const numName1 = Number(name1), numName2 = Number(name2)
            if (!isNaN(numName1) && !isNaN(numName2)) return numName1 - numName2

            const dateName1 = Date.parse(name1), dateName2 = Date.parse(name2)
            if (!isNaN(dateName1) && !isNaN(dateName2)) return dateName1 - dateName2

            return name2 < name1 ? 1 : -1
          })
        }
        return { groupedBy, groups }
      }, [initialGroups, m.columns, m.groups]),
      initGroups = React.useCallback(() => {
        setGroupByKey(groupByKey => {

Review comment (bug):
Isn't there a bug? If the column is a `time` data type, all groups should have the same format, not just non-empty ones. Assuming by code only though, so you gotta try it out. If so, please fix and add accompanying unit test.

Code after:
            : new Set<S>()
      }, [m.groups, groupByKey, items]),
      makeGroups = React.useCallback((groupByKey: S, filteredItems: (Fluent.IObjectWithKey & Dict<any>)[]) => {
        const allGroups = [...groupNames].reduce((acc, groupName) => {
          acc[groupName] = { key: groupName, name: groupName, startIndex: 0, count: 0, isCollapsed: getIsCollapsed(groupName, expandedRefs.current) }
          return acc
        }, {} as Dict<Fluent.IGroup>)
        let
          groups: Fluent.IGroup[],
          groupedBy: Dict<any> = []

        if (m.groups) {
          filteredItems.forEach(({ group }, idx) => {
            allGroups[group].count === 0
              ? allGroups[group] = { ...allGroups[group], startIndex: idx, count: 1 }
              : allGroups[group].count++
          })
          groups = Object.values(allGroups)
        } else {
          let prevSum = 0
          groupedBy = groupByF(filteredItems, groupByKey)
          const
            groupedByKeys = Object.keys(groupedBy),
            groupByColType = m.columns.find(c => c.name === groupByKey)?.data_type

          groupedByKeys.forEach((key, i) => {
            if (i !== 0) {
              const prevKey = groupedByKeys[i - 1]
              prevSum += groupedBy[prevKey].length
            }
            allGroups[key] = { key, name: key, startIndex: prevSum, count: groupedBy[key].length, isCollapsed: getIsCollapsed(key, expandedRefs.current) }
          })

          if (groupByColType === 'time') Object.keys(allGroups).forEach(key => { allGroups[key].name = valueToDateString(key) })

          groups = Object.values(allGroups).sort(({ name: name1 }, { name: name2 }) => {
            const numName1 = Number(name1), numName2 = Number(name2)
            if (!isNaN(numName1) && !isNaN(numName2)) return numName1 - numName2

            const dateName1 = Date.parse(name1), dateName2 = Date.parse(name2)
            if (!isNaN(dateName1) && !isNaN(dateName2)) return dateName1 - dateName2

            return name2 < name1 ? 1 : -1
          })
        }
        return { groupedBy, groups }
      }, [groupNames, m.columns, m.groups]),
      initGroups = React.useCallback(() => {
        setGroupByKey(groupByKey => {
          setFilteredItems(filteredItems => {
            const { groupedBy, groups } = makeGroups(groupByKey, filteredItems)