diff --git a/openbis_ng_ui/src/js/components/common/grid/Grid.jsx b/openbis_ng_ui/src/js/components/common/grid/Grid.jsx
index 5a71bb70454f1c43ed77f525383acf234f9ea8f2..2168ece491940843eca96820f4b0b20045e6f752 100644
--- a/openbis_ng_ui/src/js/components/common/grid/Grid.jsx
+++ b/openbis_ng_ui/src/js/components/common/grid/Grid.jsx
@@ -73,8 +73,11 @@ class Grid extends React.PureComponent {
   }
 
   componentDidUpdate(prevProps) {
-    if (this.props.rows !== prevProps.rows) {
-      this.controller.updateAllRows(this.props.rows)
+    if (
+      this.props.rows !== prevProps.rows ||
+      this.props.totalCount !== prevProps.totalCount
+    ) {
+      this.controller.updateRows(this.props.rows, this.props.totalCount)
     }
     if (this.props.selectedRowId !== prevProps.selectedRowId) {
       this.controller.updateSelectedRowId(this.props.selectedRowId)
@@ -101,8 +104,8 @@ class Grid extends React.PureComponent {
       pageSize,
       columns,
       currentRows,
-      sortedRows,
-      selectedRow
+      selectedRow,
+      totalCount
     } = this.state
 
     return (
@@ -136,7 +139,7 @@ class Grid extends React.PureComponent {
           </div>
           <div className={classes.tableFooter}>
             <GridPaging
-              count={sortedRows.length}
+              count={totalCount}
               page={page}
               pageSize={pageSize}
               onPageChange={this.controller.handlePageChange}
diff --git a/openbis_ng_ui/src/js/components/common/grid/GridController.js b/openbis_ng_ui/src/js/components/common/grid/GridController.js
index 20208cc6ac34a9f8c05454dd8083d452cd914535..739d984717bca642ee4f840e1ea6eb7fd87aaed7 100644
--- a/openbis_ng_ui/src/js/components/common/grid/GridController.js
+++ b/openbis_ng_ui/src/js/components/common/grid/GridController.js
@@ -41,13 +41,14 @@ export default class GridController {
       page: 0,
       pageSize: 10,
       columns,
-      allRows: [],
+      rows: [],
       filteredRows: [],
       sortedRows: [],
       currentRows: [],
       selectedRow: null,
       sort: initialSort,
-      sortDirection: initialSortDirection
+      sortDirection: initialSortDirection,
+      totalCount: 0
     })
 
     this.context = context
@@ -137,11 +138,8 @@ export default class GridController {
   }
 
   async load() {
-    const { rows, selectedRowId } = this.context.getProps()
-
     await this._loadSettings()
-    await this.updateAllRows(rows)
-    await this.updateSelectedRowId(selectedRowId)
+    await this._loadRows()
 
     await this.context.setState(() => ({
       loaded: true
@@ -226,11 +224,37 @@ export default class GridController {
     openbis.updatePersons([update])
   }
 
-  async updateAllRows(rows) {
-    const { allRows } = this.context.getState()
+  async _loadRows() {
+    const { load, rows } = this.context.getProps()
+
+    if (load) {
+      const {
+        columns,
+        filters,
+        sort,
+        sortDirection,
+        page,
+        pageSize
+      } = this.context.getState()
+
+      await load({
+        columns,
+        filters,
+        page,
+        pageSize,
+        sort,
+        sortDirection
+      })
+    } else {
+      await this.updateRows(rows, rows.length)
+    }
+  }
+
+  async updateRows(newRows, newTotalCount) {
+    const { rows, totalCount } = this.context.getState()
 
-    if (allRows !== rows) {
-      await this._recalculateCurrentRows(rows)
+    if (newRows !== rows || newTotalCount !== totalCount) {
+      await this._recalculateCurrentRows(newRows, newTotalCount)
     }
   }
 
@@ -242,36 +266,51 @@ export default class GridController {
     }
   }
 
-  async _recalculateCurrentRows(rows) {
+  async _recalculateCurrentRows(newRows, newTotalCount) {
+    const { load } = this.context.getProps()
+
     const {
-      allRows,
+      rows,
       columns,
       filters,
       sort,
       sortDirection,
       page,
-      pageSize
+      pageSize,
+      totalCount
     } = this.context.getState()
 
-    if (!rows) {
-      rows = allRows
-    }
-
-    const filteredRows = this._filter(rows, columns, filters)
+    newRows = newRows || rows
+    newTotalCount = newTotalCount || totalCount
 
-    const pageCount = Math.max(Math.ceil(filteredRows.length / pageSize), 1)
-    const newPage = Math.min(page, pageCount - 1)
+    if (load) {
+      const pageCount = Math.max(Math.ceil(newTotalCount / pageSize), 1)
+      const newPage = Math.min(page, pageCount - 1)
 
-    const sortedRows = this._sort(filteredRows, columns, sort, sortDirection)
-    const currentRows = this._page(sortedRows, newPage, pageSize)
+      await this.context.setState({
+        rows: newRows,
+        filteredRows: [],
+        sortedRows: [],
+        currentRows: newRows,
+        page: newPage,
+        totalCount: newTotalCount
+      })
+    } else {
+      const filteredRows = this._filter(newRows, columns, filters)
+      const pageCount = Math.max(Math.ceil(filteredRows.length / pageSize), 1)
+      const newPage = Math.min(page, pageCount - 1)
+      const sortedRows = this._sort(filteredRows, columns, sort, sortDirection)
+      const currentRows = this._page(sortedRows, newPage, pageSize)
 
-    await this.context.setState({
-      allRows: rows,
-      filteredRows,
-      sortedRows,
-      currentRows,
-      page: newPage
-    })
+      await this.context.setState({
+        rows: newRows,
+        filteredRows,
+        sortedRows,
+        currentRows,
+        page: newPage,
+        totalCount: filteredRows.length
+      })
+    }
 
     const { selectedRow } = this.context.getState()
 
@@ -330,7 +369,7 @@ export default class GridController {
     }
   }
 
-  handleFilterChange(column, filter) {
+  async handleFilterChange(column, filter) {
     const state = this.context.getState()
 
     let filters = {
@@ -338,17 +377,16 @@ export default class GridController {
       [column]: filter
     }
 
-    this.context
-      .setState(() => ({
-        page: 0,
-        filters
-      }))
-      .then(() => {
-        this._recalculateCurrentRows()
-      })
+    await this.context.setState(() => ({
+      page: 0,
+      filters
+    }))
+
+    await this._loadRows()
+    await this._recalculateCurrentRows()
   }
 
-  handleColumnVisibleChange(name) {
+  async handleColumnVisibleChange(name) {
     const state = this.context.getState()
 
     let columns = state.columns.map(column => {
@@ -362,16 +400,14 @@ export default class GridController {
       }
     })
 
-    this.context
-      .setState(() => ({
-        columns
-      }))
-      .then(() => {
-        this._saveSettings()
-      })
+    await this.context.setState(() => ({
+      columns
+    }))
+
+    this._saveSettings()
   }
 
-  handleColumnOrderChange(sourceIndex, destinationIndex) {
+  async handleColumnOrderChange(sourceIndex, destinationIndex) {
     const state = this.context.getState()
 
     let columns = [...state.columns]
@@ -379,59 +415,56 @@ export default class GridController {
     columns.splice(sourceIndex, 1)
     columns.splice(destinationIndex, 0, source)
 
-    this.context
-      .setState(() => ({
-        columns
-      }))
-      .then(() => {
-        this._saveSettings()
-      })
+    await this.context.setState(() => ({
+      columns
+    }))
+
+    this._saveSettings()
   }
 
-  handleSortChange(column) {
+  async handleSortChange(column) {
     if (!column.sortable) {
       return
     }
 
-    this.context
-      .setState(state => {
-        if (column.name === state.sort) {
-          return {
-            sortDirection: state.sortDirection === 'asc' ? 'desc' : 'asc'
-          }
-        } else {
-          return {
-            sort: column.name,
-            sortDirection: 'asc'
-          }
+    await this.context.setState(state => {
+      if (column.name === state.sort) {
+        return {
+          sortDirection: state.sortDirection === 'asc' ? 'desc' : 'asc'
         }
-      })
-      .then(() => {
-        this._saveSettings()
-        this._recalculateCurrentRows()
-      })
+      } else {
+        return {
+          sort: column.name,
+          sortDirection: 'asc'
+        }
+      }
+    })
+
+    this._saveSettings()
+
+    await this._loadRows()
+    await this._recalculateCurrentRows()
   }
 
-  handlePageChange(page) {
-    this.context
-      .setState(() => ({
-        page
-      }))
-      .then(() => {
-        this._recalculateCurrentRows()
-      })
+  async handlePageChange(page) {
+    await this.context.setState(() => ({
+      page
+    }))
+
+    await this._loadRows()
+    await this._recalculateCurrentRows()
   }
 
-  handlePageSizeChange(pageSize) {
-    this.context
-      .setState(() => ({
-        page: 0,
-        pageSize
-      }))
-      .then(() => {
-        this._saveSettings()
-        this._recalculateCurrentRows()
-      })
+  async handlePageSizeChange(pageSize) {
+    await this.context.setState(() => ({
+      page: 0,
+      pageSize
+    }))
+
+    this._saveSettings()
+
+    await this._loadRows()
+    await this._recalculateCurrentRows()
   }
 
   handleRowSelect(row) {
diff --git a/openbis_ng_ui/src/js/components/tools/common/HistoryGrid.jsx b/openbis_ng_ui/src/js/components/tools/common/HistoryGrid.jsx
index 139d2db68b22867276ab21137516bc318d6c383e..e7de3370a06f2c2d8597e7bd0861120cc3cd9ce6 100644
--- a/openbis_ng_ui/src/js/components/tools/common/HistoryGrid.jsx
+++ b/openbis_ng_ui/src/js/components/tools/common/HistoryGrid.jsx
@@ -1,99 +1,196 @@
+import _ from 'lodash'
 import React from 'react'
+import autoBind from 'auto-bind'
 import Grid from '@src/js/components/common/grid/Grid.jsx'
 import UserLink from '@src/js/components/common/link/UserLink.jsx'
 import Collapse from '@material-ui/core/Collapse'
 import Link from '@material-ui/core/Link'
+import FormUtil from '@src/js/components/common/form/FormUtil.js'
 import openbis from '@src/js/services/openbis.js'
 import messages from '@src/js/common/messages.js'
 import date from '@src/js/common/date.js'
 import ids from '@src/js/common/consts/ids.js'
+import store from '@src/js/store/store.js'
+import actions from '@src/js/store/actions/actions.js'
 import logger from '@src/js/common/logger.js'
 
 class HistoryGrid extends React.PureComponent {
   constructor(props) {
     super(props)
+    autoBind(this)
 
     this.state = {
-      shown: {}
+      rows: [],
+      totalCount: 0
     }
   }
 
-  handleVisibilityChange(row, fieldName) {
-    const { onRowChange } = this.props
-    if (onRowChange) {
-      onRowChange(row.id, {
-        [fieldName]: {
-          ...row[fieldName],
-          visible: !row[fieldName].visible
-        }
-      })
+  async load(params) {
+    try {
+      await this.loadHistory(this.props.eventType, params)
+    } catch (error) {
+      store.dispatch(actions.errorChange(error))
     }
   }
 
+  async loadHistory(eventType, { page, pageSize, sort, sortDirection }) {
+    const criteria = new openbis.EventSearchCriteria()
+    criteria.withEventType().thatEquals(eventType)
+
+    const fo = new openbis.EventFetchOptions()
+    fo.withRegistrator()
+    fo.from(page * pageSize)
+    fo.count(pageSize)
+
+    if (sort && sortDirection) {
+      fo.sortBy()[sort]()[sortDirection]()
+    }
+
+    const result = await openbis.searchEvents(criteria, fo)
+
+    const rows = result.objects.map(event => ({
+      id: _.get(event, 'id'),
+      eventType: FormUtil.createField({
+        value: _.get(event, 'eventType')
+      }),
+      entityType: FormUtil.createField({
+        value: _.get(event, 'entityType')
+      }),
+      entitySpace: FormUtil.createField({
+        value: _.get(event, 'entitySpace')
+      }),
+      entityProject: FormUtil.createField({
+        value: _.get(event, 'entityProject')
+      }),
+      entityRegistrator: FormUtil.createField({
+        value: _.get(event, 'entityRegistrator')
+      }),
+      entityRegistrationDate: FormUtil.createField({
+        value: _.get(event, 'entityRegistrationDate')
+      }),
+      identifier: FormUtil.createField({
+        value: _.get(event, 'identifier')
+      }),
+      description: FormUtil.createField({
+        value: _.get(event, 'description')
+      }),
+      reason: FormUtil.createField({
+        value: _.get(event, 'reason')
+      }),
+      content: FormUtil.createField({
+        value: _.get(event, 'content'),
+        visible: false
+      }),
+      registrator: FormUtil.createField({
+        value: _.get(event, 'registrator.userId')
+      }),
+      registrationDate: FormUtil.createField({
+        value: _.get(event, 'registrationDate')
+      })
+    }))
+
+    this.setState({
+      rows,
+      totalCount: result.totalCount
+    })
+  }
+
+  handleRowChange(row, change) {
+    const rows = this.state.rows
+    this.setState(state => {
+      const index = rows.findIndex(r => r.id === row.id)
+      if (index !== -1) {
+        const row = rows[index]
+        const newRows = Array.from(rows)
+        newRows[index] = {
+          ...row,
+          ...change
+        }
+        return {
+          ...state,
+          rows: newRows
+        }
+      }
+    })
+  }
+
+  handleVisibilityChange(row, fieldName) {
+    this.handleRowChange(row, {
+      [fieldName]: {
+        ...row[fieldName],
+        visible: !row[fieldName].visible
+      }
+    })
+  }
+
   render() {
     logger.log(logger.DEBUG, 'HistoryGrid.render')
 
-    const {
-      rows,
-      selectedRowId,
-      onSelectedRowChange,
-      controllerRef
-    } = this.props
+    const { rows, totalCount } = this.state
 
     return (
       <Grid
         id={this.getId()}
         header={this.getHeader()}
-        controllerRef={controllerRef}
         columns={[
           {
             name: 'eventType',
             label: messages.get(messages.EVENT_TYPE),
+            sortable: false,
             getValue: ({ row }) => row.eventType.value
           },
           {
             name: 'entityType',
             label: messages.get(messages.ENTITY_TYPE),
+            sortable: false,
             getValue: ({ row }) => row.entityType.value
           },
           {
-            name: 'entityIdentifier',
+            name: 'identifier',
             label: messages.get(messages.ENTITY_IDENTIFIER),
+            sortable: true,
             getValue: ({ row }) => row.identifier.value
           },
           {
             name: 'entitySpace',
             label: messages.get(messages.ENTITY_SPACE),
+            sortable: false,
             getValue: ({ row }) => row.entitySpace.value
           },
           {
             name: 'entityProject',
             label: messages.get(messages.ENTITY_PROJECT),
+            sortable: false,
             getValue: ({ row }) => row.entityProject.value
           },
           {
             name: 'entityRegistrator',
             label: messages.get(messages.ENTITY_REGISTRATOR),
+            sortable: false,
             getValue: ({ row }) => row.entityRegistrator.value
           },
           {
             name: 'entityRegistrationDate',
             label: messages.get(messages.ENTITY_REGISTRATION_DATE),
+            sortable: false,
             getValue: ({ row }) => date.format(row.entityRegistrationDate.value)
           },
           {
             name: 'description',
             label: messages.get(messages.DESCRIPTION),
+            sortable: false,
             getValue: ({ row }) => row.description.value
           },
           {
             name: 'reason',
             label: messages.get(messages.REASON),
+            sortable: false,
             getValue: ({ row }) => row.reason.value
           },
           {
             name: 'content',
             label: messages.get(messages.CONTENT),
+            sortable: false,
             getValue: ({ row }) => row.content.value,
             renderValue: ({ row }) => {
               const { value, visible } = row.content
@@ -124,6 +221,7 @@ class HistoryGrid extends React.PureComponent {
           {
             name: 'registrator',
             label: messages.get(messages.USER),
+            sortable: false,
             getValue: ({ row }) => row.registrator.value,
             renderValue: ({ value }) => {
               return <UserLink userId={value} />
@@ -132,12 +230,14 @@ class HistoryGrid extends React.PureComponent {
           {
             name: 'registrationDate',
             label: messages.get(messages.DATE),
+            sortable: true,
+            sort: 'desc',
             getValue: ({ row }) => date.format(row.registrationDate.value)
           }
         ]}
         rows={rows}
-        selectedRowId={selectedRowId}
-        onSelectedRowChange={onSelectedRowChange}
+        totalCount={totalCount}
+        load={this.load}
       />
     )
   }
diff --git a/openbis_ng_ui/src/js/components/tools/form/history/HistoryForm.jsx b/openbis_ng_ui/src/js/components/tools/form/history/HistoryForm.jsx
index 94461d1c751f92b378466fc780cdd2d77f315206..5ff1d8251ae6143aab52a9259d52b485179e5b5a 100644
--- a/openbis_ng_ui/src/js/components/tools/form/history/HistoryForm.jsx
+++ b/openbis_ng_ui/src/js/components/tools/form/history/HistoryForm.jsx
@@ -1,127 +1,20 @@
-import _ from 'lodash'
 import React from 'react'
-import autoBind from 'auto-bind'
-import { connect } from 'react-redux'
-import { withStyles } from '@material-ui/core/styles'
 import GridContainer from '@src/js/components/common/grid/GridContainer.jsx'
 import HistoryGrid from '@src/js/components/tools/common/HistoryGrid.jsx'
-import FormUtil from '@src/js/components/common/form/FormUtil.js'
-import openbis from '@src/js/services/openbis.js'
-import store from '@src/js/store/store.js'
-import actions from '@src/js/store/actions/actions.js'
 import logger from '@src/js/common/logger.js'
 
-const styles = () => ({})
-
 class HistoryForm extends React.PureComponent {
-  constructor(props) {
-    super(props)
-    autoBind(this)
-
-    this.state = {
-      loaded: false,
-      selection: null
-    }
-  }
-
-  componentDidMount() {
-    this.load()
-  }
-
-  async load() {
-    try {
-      const rows = await this.loadEvents(this.props.object.id)
-      this.setState(() => ({
-        rows,
-        loaded: true
-      }))
-    } catch (error) {
-      store.dispatch(actions.errorChange(error))
-    }
-  }
-
-  async loadEvents(eventType) {
-    const criteria = new openbis.EventSearchCriteria()
-    criteria.withEventType().thatEquals(eventType)
-
-    const fo = new openbis.EventFetchOptions()
-    fo.withRegistrator()
-
-    const result = await openbis.searchEvents(criteria, fo)
-
-    return result.objects.map(event => ({
-      id: _.get(event, 'id'),
-      eventType: FormUtil.createField({ value: _.get(event, 'eventType') }),
-      entityType: FormUtil.createField({ value: _.get(event, 'entityType') }),
-      entitySpace: FormUtil.createField({
-        value: _.get(event, 'entitySpace')
-      }),
-      entityProject: FormUtil.createField({
-        value: _.get(event, 'entityProject')
-      }),
-      entityRegistrator: FormUtil.createField({
-        value: _.get(event, 'entityRegistrator')
-      }),
-      entityRegistrationDate: FormUtil.createField({
-        value: _.get(event, 'entityRegistrationDate')
-      }),
-      identifier: FormUtil.createField({
-        value: _.get(event, 'identifier')
-      }),
-      description: FormUtil.createField({
-        value: _.get(event, 'description')
-      }),
-      reason: FormUtil.createField({
-        value: _.get(event, 'reason')
-      }),
-      content: FormUtil.createField({
-        value: _.get(event, 'content'),
-        visible: false
-      }),
-      registrator: FormUtil.createField({
-        value: _.get(event, 'registrator.userId')
-      }),
-      registrationDate: FormUtil.createField({
-        value: _.get(event, 'registrationDate')
-      })
-    }))
-  }
-
-  handleRowChange(rowId, change) {
-    const rows = this.state.rows
-    this.setState(state => {
-      const index = rows.findIndex(row => row.id === rowId)
-      if (index !== -1) {
-        const row = rows[index]
-        const newRows = Array.from(rows)
-        newRows[index] = {
-          ...row,
-          ...change
-        }
-        return {
-          ...state,
-          rows: newRows
-        }
-      }
-    })
-  }
-
   render() {
     logger.log(logger.DEBUG, 'HistoryForm.render')
 
     const { id } = this.props.object
-    const { rows } = this.state
 
     return (
       <GridContainer>
-        <HistoryGrid
-          eventType={id}
-          rows={rows}
-          onRowChange={this.handleRowChange}
-        />
+        <HistoryGrid eventType={id} />
       </GridContainer>
     )
   }
 }
 
-export default _.flow(connect(), withStyles(styles))(HistoryForm)
+export default HistoryForm