<commit_before>H2O.FrameOutput = (_, _go, _frame) ->
  MaxItemsPerPage = 20

  _grid = signal null
  _chunkSummary = signal null
  _distributionSummary = signal null
  _columnNameSearchTerm = signal null
  _currentPage = signal 0
  _maxPages = signal 10000 #TODO FIXME 
  _canGoToPreviousPage = lift _currentPage, (index) -> index > 0
  _canGoToNextPage = lift _maxPages, _currentPage, (maxPages, index) -> index < maxPages - 1

  renderPlot = (container, render) ->
    render (error, vis) ->
      if error
        debug error
      else
        container vis.element

  renderGrid = (render) ->
    render (error, vis) ->
      if error
        debug error
      else
        $('a', vis.element).on 'click', (e) ->
          $a = $ e.target
          if 'label' is $a.attr 'data-type'
            _.insertAndExecuteCell 'cs', "getColumnSummary #{stringify _frame.frame_id.name}, #{stringify $a.attr 'data-key'}"

        _grid vis.element

  createModel = ->
    _.insertAndExecuteCell 'cs', "assist buildModel, null, training_frame: #{stringify _frame.frame_id.name}"

  inspect = ->
    _.insertAndExecuteCell 'cs', "inspect getFrameSummary #{stringify _frame.frame_id.name}"

  inspectData = ->
    _.insertAndExecuteCell 'cs', "getFrameData #{stringify _frame.frame_id.name}"

  splitFrame = ->
    _.insertAndExecuteCell 'cs', "assist splitFrame, #{stringify _frame.frame_id.name}"

  predict = ->
    _.insertAndExecuteCell 'cs', "predict frame: #{stringify _frame.frame_id.name}"

  download = ->
    window.open "/3/DownloadDataset?frame_id=#{encodeURIComponent _frame.frame_id.name}", '_blank'

  deleteFrame = ->
    _.confirm 'Are you sure you want to delete this frame?', { acceptCaption: 'Delete Frame', declineCaption: 'Cancel' }, (accept) ->
      if accept
        _.insertAndExecuteCell 'cs', "deleteFrame #{stringify _frame.frame_id.name}"

  renderFrame = (frame) ->
    renderGrid _.plot (g) ->
      g(
        g.select()
        g.from _.inspect 'columns', frame
      )

    renderPlot _chunkSummary, _.plot (g) ->
      g(
        g.select()
        g.from _.inspect 'Chunk compression summary', frame
      )

    renderPlot _distributionSummary, _.plot (g) ->
      g(
        g.select()
        g.from _.inspect 'Frame distribution summary', frame
      )

  _lastUsedSearchTerm = null 
  refreshColumns = (pageIndex) ->
    searchTerm = _columnNameSearchTerm()
    if searchTerm isnt _lastUsedSearchTerm
      pageIndex = 0
       
    _.requestFrameSummarySliceE _frame.frame_id.name, searchTerm, pageIndex * MaxItemsPerPage, MaxItemsPerPage, (error, frame) ->
      if error
        #TODO
      else
        _lastUsedSearchTerm = searchTerm
        _currentPage pageIndex
        renderFrame frame
       
  goToPreviousPage = ->
    currentPage = _currentPage()
    if currentPage > 0
      refreshColumns currentPage - 1
    return

  goToNextPage = ->
    currentPage = _currentPage()
    if currentPage < _maxPages() - 1
      refreshColumns currentPage + 1
    return

  react _columnNameSearchTerm, throttle refreshColumns, 500

  renderFrame _frame

  defer _go

  key: _frame.frame_id.name
  rowCount: _frame.rows
  columnCount: _frame.columns.length
  size: Flow.Util.formatBytes _frame.byte_size
  chunkSummary: _chunkSummary
  distributionSummary: _distributionSummary
  columnNameSearchTerm: _columnNameSearchTerm
  grid: _grid
  inspect: inspect
  createModel: createModel
  inspectData: inspectData
  splitFrame: splitFrame
  predict: predict
  download: download
  canGoToPreviousPage: _canGoToPreviousPage
  canGoToNextPage: _canGoToNextPage
  goToPreviousPage: goToPreviousPage
  goToNextPage: goToNextPage
  deleteFrame: deleteFrame<commit_msg>Handle max pages in frame summary output<commit_after>H2O.FrameOutput = (_, _go, _frame) ->
  MaxItemsPerPage = 20

  _grid = signal null
  _chunkSummary = signal null
  _distributionSummary = signal null
  _columnNameSearchTerm = signal null
  _currentPage = signal 0
  _maxPages = signal Math.ceil _frame.total_column_count / MaxItemsPerPage
  _canGoToPreviousPage = lift _currentPage, (index) -> index > 0
  _canGoToNextPage = lift _maxPages, _currentPage, (maxPages, index) -> index < maxPages - 1

  renderPlot = (container, render) ->
    render (error, vis) ->
      if error
        debug error
      else
        container vis.element

  renderGrid = (render) ->
    render (error, vis) ->
      if error
        debug error
      else
        $('a', vis.element).on 'click', (e) ->
          $a = $ e.target
          if 'label' is $a.attr 'data-type'
            _.insertAndExecuteCell 'cs', "getColumnSummary #{stringify _frame.frame_id.name}, #{stringify $a.attr 'data-key'}"

        _grid vis.element

  createModel = ->
    _.insertAndExecuteCell 'cs', "assist buildModel, null, training_frame: #{stringify _frame.frame_id.name}"

  inspect = ->
    _.insertAndExecuteCell 'cs', "inspect getFrameSummary #{stringify _frame.frame_id.name}"

  inspectData = ->
    _.insertAndExecuteCell 'cs', "getFrameData #{stringify _frame.frame_id.name}"

  splitFrame = ->
    _.insertAndExecuteCell 'cs', "assist splitFrame, #{stringify _frame.frame_id.name}"

  predict = ->
    _.insertAndExecuteCell 'cs', "predict frame: #{stringify _frame.frame_id.name}"

  download = ->
    window.open "/3/DownloadDataset?frame_id=#{encodeURIComponent _frame.frame_id.name}", '_blank'

  deleteFrame = ->
    _.confirm 'Are you sure you want to delete this frame?', { acceptCaption: 'Delete Frame', declineCaption: 'Cancel' }, (accept) ->
      if accept
        _.insertAndExecuteCell 'cs', "deleteFrame #{stringify _frame.frame_id.name}"

  renderFrame = (frame) ->
    renderGrid _.plot (g) ->
      g(
        g.select()
        g.from _.inspect 'columns', frame
      )

    renderPlot _chunkSummary, _.plot (g) ->
      g(
        g.select()
        g.from _.inspect 'Chunk compression summary', frame
      )

    renderPlot _distributionSummary, _.plot (g) ->
      g(
        g.select()
        g.from _.inspect 'Frame distribution summary', frame
      )

  _lastUsedSearchTerm = null 
  refreshColumns = (pageIndex) ->
    searchTerm = _columnNameSearchTerm()
    if searchTerm isnt _lastUsedSearchTerm
      pageIndex = 0
       
    startIndex = pageIndex * MaxItemsPerPage
    itemCount = if startIndex + MaxItemsPerPage < _frame.total_column_count then MaxItemsPerPage else _frame.total_column_count - startIndex
    _.requestFrameSummarySliceE _frame.frame_id.name, searchTerm, startIndex, itemCount, (error, frame) ->
      if error
        #TODO
      else
        _lastUsedSearchTerm = searchTerm
        _currentPage pageIndex
        renderFrame frame
       
  goToPreviousPage = ->
    currentPage = _currentPage()
    if currentPage > 0
      refreshColumns currentPage - 1
    return

  goToNextPage = ->
    currentPage = _currentPage()
    if currentPage < _maxPages() - 1
      refreshColumns currentPage + 1
    return

  react _columnNameSearchTerm, throttle refreshColumns, 500

  renderFrame _frame

  defer _go

  key: _frame.frame_id.name
  rowCount: _frame.rows
  columnCount: _frame.total_column_count
  size: Flow.Util.formatBytes _frame.byte_size
  chunkSummary: _chunkSummary
  distributionSummary: _distributionSummary
  columnNameSearchTerm: _columnNameSearchTerm
  grid: _grid
  inspect: inspect
  createModel: createModel
  inspectData: inspectData
  splitFrame: splitFrame
  predict: predict
  download: download
  canGoToPreviousPage: _canGoToPreviousPage
  canGoToNextPage: _canGoToNextPage
  goToPreviousPage: goToPreviousPage
  goToNextPage: goToNextPage
  deleteFrame: deleteFrame
{'fraction_non_alphanumeric': 0.09450059062869143, 'fraction_numerical': 0.004593778711116945, 'mean_word_length': 3.1166936790923825, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 55, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2123996', 'n_tokens_mistral': 2334, 'n_tokens_neox': 2254, 'n_words': 583}