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

Code before:
          data = toCSV([m.columns.map(({ label, name }) => label || name), ...m.rows.map(({ cells }) => cells)]),
          a = document.createElement('a'),
          blob = new Blob([data], { type: "octet/stream" }),
          url = window.URL.createObjectURL(blob)

        a.href = url
        a.download = 'exported_data.csv'
        a.click()

        window.URL.revokeObjectURL(url)
      },
      onRenderItemColumn = (item?: Fluent.IObjectWithKey & Dict<any>, _idx?: U, col?: WaveColumn) => {
        if (!item || !col) return <span />

        // HACK: prevent Safari from showing a default tooltip - https://github.com/microsoft/fluentui/issues/13868
        const hostStyles: Partial<ITooltipHostStyles> = {
          root: {
            '::after': {
              content: '',
              display: 'block',
            }
          },
        }

        const TooltipWrapper = ({ children }: { children: string }) => {
          if (col.overflow === 'tooltip') return <TooltipHost styles={hostStyles} id={item.key as string} content={children} overflowMode={TooltipOverflowMode.Parent} title={children}>{children}</TooltipHost>
          if (col.overflow === 'wrap') return <span style={{ whiteSpace: col.overflow === 'wrap' ? 'normal' : undefined }}>{children}</span>
          return <>{children}</>
        }

        let v = item[col.fieldName as S]
        if (col.cellType?.progress) return <XProgressTableCellType model={col.cellType.progress} progress={item[col.key]} />
        if (col.cellType?.icon) return <XIconTableCellType model={col.cellType.icon} icon={item[col.key]} />
        if (col.cellType?.tag) return <XTagTableCellType model={col.cellType.tag} serializedTags={item[col.key]} />
        if (col.dataType === 'time') v = new Date(v).toLocaleString()
        if (col.key === primaryColumnKey && !isMultiple) {
          const onClick = () => {
            wave.args[m.name] = [item.key as S]
            wave.push()
          }
          return <Fluent.Link onClick={onClick}><TooltipWrapper>{v}</TooltipWrapper></Fluent.Link>
        }

        return <TooltipWrapper>{v}</TooltipWrapper>
      }

    // HACK: React stale closures - https://reactjs.org/docs/hooks-faq.html#why-am-i-seeing-stale-props-or-state-inside-my-function
    // TODO: Find a reasonable way of doing this.
    React.useEffect(() => { { selectedFiltersRef.current = selectedFilters } }, [selectedFilters])

    return (

Review comment (bug):
```suggestion
          if (col.overflow === 'tooltip') return (
            <Fluent.TooltipHost
              id={item.key as S}
              // HACK: prevent Safari from showing a default tooltip - https://github.com/microsoft/fluentui/issues/13868
              styles={{ root: { '::after': { content: '', display: 'block' } } }}
              content={children}
              overflowMode={Fluent.TooltipOverflowMode.Parent}
              title={children}
            >{children}</Fluent.TooltipHost>
          )
```

Code after:
              content={children}
              overflowMode={Fluent.TooltipOverflowMode.Parent}
              title={children}
            >{children}</Fluent.TooltipHost>
          )
          return <>{children}</>
        }

        let v = item[col.fieldName as S]
        if (col.cellType?.progress) return <XProgressTableCellType model={col.cellType.progress} progress={item[col.key]} />
        if (col.cellType?.icon) return <XIconTableCellType model={col.cellType.icon} icon={item[col.key]} />
        if (col.cellType?.tag) return <XTagTableCellType model={col.cellType.tag} serializedTags={item[col.key]} />
        if (col.dataType === 'time') v = new Date(v).toLocaleString()
        if (col.key === primaryColumnKey && !isMultiple) {
          const onClick = () => {
            wave.args[m.name] = [item.key as S]
            wave.push()
          }
          return <Fluent.Link onClick={onClick}><TooltipWrapper>{v}</TooltipWrapper></Fluent.Link>
        }

        return <TooltipWrapper>{v}</TooltipWrapper>
      }

    // HACK: React stale closures - https://reactjs.org/docs/hooks-faq.html#why-am-i-seeing-stale-props-or-state-inside-my-function
    // TODO: Find a reasonable way of doing this.
    React.useEffect(() => { { selectedFiltersRef.current = selectedFilters } }, [selectedFilters])

    return (
      <>
        <Fluent.DetailsList
          styles={styles}
          items={filteredItems}
          columns={columns}
          constrainMode={Fluent.ConstrainMode.unconstrained}
          layoutMode={Fluent.DetailsListLayoutMode.fixedColumns}
          groups={groups}
          selection={selection}
          selectionMode={isMultiple ? Fluent.SelectionMode.multiple : Fluent.SelectionMode.none}
          selectionPreservedOnEmptyClick
          onItemInvoked={isMultiple ? undefined : onItemInvoked}
          onRenderRow={onRenderRow}
          onRenderItemColumn={onRenderItemColumn}
          onRenderDetailsHeader={onRenderDetailsHeader}
          checkboxVisibility={checkboxVisibilityMap[m.checkbox_visibility || 'on-hover']}
        />
        {colContextMenuList && <Fluent.ContextualMenu {...colContextMenuList} />}
      </>
    )
  }