You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by vi...@apache.org on 2023/12/04 19:51:24 UTC

(superset) branch master updated: chore: harmonize and clean up list views (#25961)

This is an automated email from the ASF dual-hosted git repository.

villebro pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git


The following commit(s) were added to refs/heads/master by this push:
     new 0b477e3f7c chore: harmonize and clean up list views (#25961)
0b477e3f7c is described below

commit 0b477e3f7c08fabdcdb0cb1bca48335685a699bf
Author: Ville Brofeldt <33...@users.noreply.github.com>
AuthorDate: Mon Dec 4 11:51:18 2023 -0800

    chore: harmonize and clean up list views (#25961)
---
 .../cypress/e2e/alerts_and_reports/alerts.test.ts  |   7 +-
 .../cypress/e2e/alerts_and_reports/reports.test.ts |   7 +-
 .../cypress/e2e/chart_list/filter.test.ts          |  16 +-
 .../cypress/e2e/chart_list/list.test.ts            |  10 +-
 .../cypress/e2e/dashboard_list/filter.test.ts      |   6 +-
 .../cypress/e2e/dashboard_list/list.test.ts        |  12 +-
 .../src/components/AuditInfo/ModifiedInfo.test.tsx |  42 +++++
 .../src/components/AuditInfo/index.tsx             |  30 ++++
 .../src/components/Datasource/DatasourceEditor.jsx |   2 +-
 .../dashboard/components/PropertiesModal/index.tsx |   2 +-
 .../src/features/annotations/AnnotationModal.tsx   |   2 +-
 .../src/features/cssTemplates/CssTemplateModal.tsx |   5 +-
 .../src/features/cssTemplates/types.ts             |  11 +-
 .../src/features/tags/TagModal.test.tsx            |   2 +
 .../src/pages/AlertReportList/index.tsx            |  74 ++++----
 superset-frontend/src/pages/AllEntities/index.tsx  |   5 +-
 .../src/pages/AnnotationLayerList/index.tsx        |  89 +++-------
 .../src/pages/AnnotationList/index.tsx             |   2 +-
 superset-frontend/src/pages/ChartList/index.tsx    | 168 +++++++++---------
 .../src/pages/CssTemplateList/index.tsx            |  88 +++-------
 .../src/pages/DashboardList/index.tsx              | 187 ++++++++++-----------
 .../src/pages/DatabaseList/DatabaseList.test.jsx   |   2 +-
 superset-frontend/src/pages/DatabaseList/index.tsx |  80 ++++++---
 .../src/pages/DatasetList/DatasetList.test.tsx     |  61 +++----
 superset-frontend/src/pages/DatasetList/index.tsx  | 109 +++++++-----
 .../src/pages/QueryHistoryList/index.tsx           |   3 +-
 .../RowLevelSecurityList.test.tsx                  |   6 +-
 .../src/pages/RowLevelSecurityList/index.tsx       |  39 ++++-
 .../src/pages/SavedQueryList/index.tsx             | 136 ++++++++-------
 superset-frontend/src/pages/Tags/index.tsx         |  68 ++++----
 .../types.ts => utils/getOwnerName.test.ts}        |  23 ++-
 .../types.ts => utils/getOwnerName.ts}             |  20 +--
 superset-frontend/src/views/CRUD/types.ts          |  11 +-
 superset/annotation_layers/api.py                  |   2 +-
 superset/charts/api.py                             |   2 +-
 superset/css_templates/api.py                      |   6 +-
 superset/dashboards/api.py                         |   2 +-
 superset/databases/api.py                          |  13 ++
 superset/datasets/api.py                           |  13 +-
 superset/queries/saved_queries/api.py              |  12 +-
 superset/reports/api.py                            |  10 +-
 superset/row_level_security/api.py                 |   7 +-
 superset/row_level_security/schemas.py             |   2 +
 superset/tags/api.py                               |   2 +-
 tests/integration_tests/css_templates/api_tests.py |  25 ++-
 tests/integration_tests/databases/api_tests.py     |   1 +
 .../queries/saved_queries/api_tests.py             |  14 +-
 47 files changed, 745 insertions(+), 691 deletions(-)

diff --git a/superset-frontend/cypress-base/cypress/e2e/alerts_and_reports/alerts.test.ts b/superset-frontend/cypress-base/cypress/e2e/alerts_and_reports/alerts.test.ts
index a695541cee..b677507a46 100644
--- a/superset-frontend/cypress-base/cypress/e2e/alerts_and_reports/alerts.test.ts
+++ b/superset-frontend/cypress-base/cypress/e2e/alerts_and_reports/alerts.test.ts
@@ -29,10 +29,9 @@ describe('Alert list view', () => {
     cy.getBySel('sort-header').eq(2).contains('Name');
     cy.getBySel('sort-header').eq(3).contains('Schedule');
     cy.getBySel('sort-header').eq(4).contains('Notification method');
-    cy.getBySel('sort-header').eq(5).contains('Created by');
-    cy.getBySel('sort-header').eq(6).contains('Owners');
-    cy.getBySel('sort-header').eq(7).contains('Modified');
-    cy.getBySel('sort-header').eq(8).contains('Active');
+    cy.getBySel('sort-header').eq(5).contains('Owners');
+    cy.getBySel('sort-header').eq(6).contains('Last modified');
+    cy.getBySel('sort-header').eq(7).contains('Active');
     // TODO Cypress won't recognize the Actions column
     // cy.getBySel('sort-header').eq(9).contains('Actions');
   });
diff --git a/superset-frontend/cypress-base/cypress/e2e/alerts_and_reports/reports.test.ts b/superset-frontend/cypress-base/cypress/e2e/alerts_and_reports/reports.test.ts
index e267d76f6f..a227fa03d7 100644
--- a/superset-frontend/cypress-base/cypress/e2e/alerts_and_reports/reports.test.ts
+++ b/superset-frontend/cypress-base/cypress/e2e/alerts_and_reports/reports.test.ts
@@ -29,10 +29,9 @@ describe('Report list view', () => {
     cy.getBySel('sort-header').eq(2).contains('Name');
     cy.getBySel('sort-header').eq(3).contains('Schedule');
     cy.getBySel('sort-header').eq(4).contains('Notification method');
-    cy.getBySel('sort-header').eq(5).contains('Created by');
-    cy.getBySel('sort-header').eq(6).contains('Owners');
-    cy.getBySel('sort-header').eq(7).contains('Modified');
-    cy.getBySel('sort-header').eq(8).contains('Active');
+    cy.getBySel('sort-header').eq(5).contains('Owners');
+    cy.getBySel('sort-header').eq(6).contains('Last modified');
+    cy.getBySel('sort-header').eq(7).contains('Active');
     // TODO Cypress won't recognize the Actions column
     // cy.getBySel('sort-header').eq(9).contains('Actions');
   });
diff --git a/superset-frontend/cypress-base/cypress/e2e/chart_list/filter.test.ts b/superset-frontend/cypress-base/cypress/e2e/chart_list/filter.test.ts
index acd11669be..00b09e2fb8 100644
--- a/superset-frontend/cypress-base/cypress/e2e/chart_list/filter.test.ts
+++ b/superset-frontend/cypress-base/cypress/e2e/chart_list/filter.test.ts
@@ -35,14 +35,14 @@ describe('Charts filters', () => {
     setFilter('Owner', 'admin user');
   });
 
-  it('should allow filtering by "Created by" correctly', () => {
-    setFilter('Created by', 'alpha user');
-    setFilter('Created by', 'admin user');
+  it('should allow filtering by "Modified by" correctly', () => {
+    setFilter('Modified by', 'alpha user');
+    setFilter('Modified by', 'admin user');
   });
 
-  it('should allow filtering by "Chart type" correctly', () => {
-    setFilter('Chart type', 'Area Chart (legacy)');
-    setFilter('Chart type', 'Bubble Chart');
+  it('should allow filtering by "Type" correctly', () => {
+    setFilter('Type', 'Area Chart (legacy)');
+    setFilter('Type', 'Bubble Chart');
   });
 
   it('should allow filtering by "Dataset" correctly', () => {
@@ -51,7 +51,7 @@ describe('Charts filters', () => {
   });
 
   it('should allow filtering by "Dashboards" correctly', () => {
-    setFilter('Dashboards', 'Unicode Test');
-    setFilter('Dashboards', 'Tabbed Dashboard');
+    setFilter('Dashboard', 'Unicode Test');
+    setFilter('Dashboard', 'Tabbed Dashboard');
   });
 });
diff --git a/superset-frontend/cypress-base/cypress/e2e/chart_list/list.test.ts b/superset-frontend/cypress-base/cypress/e2e/chart_list/list.test.ts
index 6664281abe..44f348edc5 100644
--- a/superset-frontend/cypress-base/cypress/e2e/chart_list/list.test.ts
+++ b/superset-frontend/cypress-base/cypress/e2e/chart_list/list.test.ts
@@ -109,14 +109,12 @@ describe('Charts list', () => {
 
     it('should load rows in list mode', () => {
       cy.getBySel('listview-table').should('be.visible');
-      cy.getBySel('sort-header').eq(1).contains('Chart');
-      cy.getBySel('sort-header').eq(2).contains('Visualization type');
+      cy.getBySel('sort-header').eq(1).contains('Name');
+      cy.getBySel('sort-header').eq(2).contains('Type');
       cy.getBySel('sort-header').eq(3).contains('Dataset');
-      // cy.getBySel('sort-header').eq(4).contains('Dashboards added to');
-      cy.getBySel('sort-header').eq(4).contains('Modified by');
+      cy.getBySel('sort-header').eq(4).contains('Owners');
       cy.getBySel('sort-header').eq(5).contains('Last modified');
-      cy.getBySel('sort-header').eq(6).contains('Created by');
-      cy.getBySel('sort-header').eq(7).contains('Actions');
+      cy.getBySel('sort-header').eq(6).contains('Actions');
     });
 
     it('should sort correctly in list mode', () => {
diff --git a/superset-frontend/cypress-base/cypress/e2e/dashboard_list/filter.test.ts b/superset-frontend/cypress-base/cypress/e2e/dashboard_list/filter.test.ts
index 4654b3b5c2..854ea541c7 100644
--- a/superset-frontend/cypress-base/cypress/e2e/dashboard_list/filter.test.ts
+++ b/superset-frontend/cypress-base/cypress/e2e/dashboard_list/filter.test.ts
@@ -35,9 +35,9 @@ describe('Dashboards filters', () => {
     setFilter('Owner', 'admin user');
   });
 
-  it('should allow filtering by "Created by" correctly', () => {
-    setFilter('Created by', 'alpha user');
-    setFilter('Created by', 'admin user');
+  it('should allow filtering by "Modified by" correctly', () => {
+    setFilter('Modified by', 'alpha user');
+    setFilter('Modified by', 'admin user');
   });
 
   it('should allow filtering by "Status" correctly', () => {
diff --git a/superset-frontend/cypress-base/cypress/e2e/dashboard_list/list.test.ts b/superset-frontend/cypress-base/cypress/e2e/dashboard_list/list.test.ts
index 9bc6eed224..7dfb7cd673 100644
--- a/superset-frontend/cypress-base/cypress/e2e/dashboard_list/list.test.ts
+++ b/superset-frontend/cypress-base/cypress/e2e/dashboard_list/list.test.ts
@@ -54,13 +54,11 @@ describe('Dashboards list', () => {
 
     it('should load rows in list mode', () => {
       cy.getBySel('listview-table').should('be.visible');
-      cy.getBySel('sort-header').eq(1).contains('Title');
-      cy.getBySel('sort-header').eq(2).contains('Modified by');
-      cy.getBySel('sort-header').eq(3).contains('Status');
-      cy.getBySel('sort-header').eq(4).contains('Modified');
-      cy.getBySel('sort-header').eq(5).contains('Created by');
-      cy.getBySel('sort-header').eq(6).contains('Owners');
-      cy.getBySel('sort-header').eq(7).contains('Actions');
+      cy.getBySel('sort-header').eq(1).contains('Name');
+      cy.getBySel('sort-header').eq(2).contains('Status');
+      cy.getBySel('sort-header').eq(3).contains('Owners');
+      cy.getBySel('sort-header').eq(4).contains('Last modified');
+      cy.getBySel('sort-header').eq(5).contains('Actions');
     });
 
     it('should sort correctly in list mode', () => {
diff --git a/superset-frontend/src/components/AuditInfo/ModifiedInfo.test.tsx b/superset-frontend/src/components/AuditInfo/ModifiedInfo.test.tsx
new file mode 100644
index 0000000000..af9d6913d8
--- /dev/null
+++ b/superset-frontend/src/components/AuditInfo/ModifiedInfo.test.tsx
@@ -0,0 +1,42 @@
+import React from 'react';
+import { render, screen, waitFor } from 'spec/helpers/testing-library';
+import '@testing-library/jest-dom';
+import userEvent from '@testing-library/user-event';
+
+import { ModifiedInfo } from '.';
+
+const TEST_DATE = '2023-11-20';
+const USER = {
+  id: 1,
+  first_name: 'Foo',
+  last_name: 'Bar',
+};
+
+test('should render a tooltip when user is provided', async () => {
+  render(<ModifiedInfo user={USER} date={TEST_DATE} />);
+
+  const dateElement = screen.getByTestId('audit-info-date');
+  expect(dateElement).toBeInTheDocument();
+  expect(screen.getByText(TEST_DATE)).toBeInTheDocument();
+  expect(screen.queryByText('Modified by: Foo Bar')).not.toBeInTheDocument();
+  userEvent.hover(dateElement);
+  const tooltip = await screen.findByRole('tooltip');
+  expect(tooltip).toBeInTheDocument();
+  expect(screen.getByText('Modified by: Foo Bar')).toBeInTheDocument();
+});
+
+test('should render only the date if username is not provided', async () => {
+  render(<ModifiedInfo date={TEST_DATE} />);
+
+  const dateElement = screen.getByTestId('audit-info-date');
+  expect(dateElement).toBeInTheDocument();
+  expect(screen.getByText(TEST_DATE)).toBeInTheDocument();
+  userEvent.hover(dateElement);
+  await waitFor(
+    () => {
+      const tooltip = screen.queryByRole('tooltip');
+      expect(tooltip).not.toBeInTheDocument();
+    },
+    { timeout: 1000 },
+  );
+});
diff --git a/superset-frontend/src/components/AuditInfo/index.tsx b/superset-frontend/src/components/AuditInfo/index.tsx
new file mode 100644
index 0000000000..24223a1554
--- /dev/null
+++ b/superset-frontend/src/components/AuditInfo/index.tsx
@@ -0,0 +1,30 @@
+import React from 'react';
+
+import Owner from 'src/types/Owner';
+import { Tooltip } from 'src/components/Tooltip';
+import getOwnerName from 'src/utils/getOwnerName';
+import { t } from '@superset-ui/core';
+
+export type ModifiedInfoProps = {
+  user?: Owner;
+  date: string;
+};
+
+export const ModifiedInfo = ({ user, date }: ModifiedInfoProps) => {
+  const dateSpan = (
+    <span className="no-wrap" data-test="audit-info-date">
+      {date}
+    </span>
+  );
+
+  if (user) {
+    const userName = getOwnerName(user);
+    const title = t('Modified by: %s', userName);
+    return (
+      <Tooltip title={title} placement="bottom">
+        {dateSpan}
+      </Tooltip>
+    );
+  }
+  return dateSpan;
+};
diff --git a/superset-frontend/src/components/Datasource/DatasourceEditor.jsx b/superset-frontend/src/components/Datasource/DatasourceEditor.jsx
index 86b5c22777..751001297a 100644
--- a/superset-frontend/src/components/Datasource/DatasourceEditor.jsx
+++ b/superset-frontend/src/components/Datasource/DatasourceEditor.jsx
@@ -1114,7 +1114,7 @@ class DatasourceEditor extends React.PureComponent {
                     <div css={{ width: 'calc(100% - 34px)', marginTop: -16 }}>
                       <Field
                         fieldKey="table_name"
-                        label={t('Dataset name')}
+                        label={t('Name')}
                         control={
                           <TextControl
                             controlId="table_name"
diff --git a/superset-frontend/src/dashboard/components/PropertiesModal/index.tsx b/superset-frontend/src/dashboard/components/PropertiesModal/index.tsx
index 92d34a4faa..3a1421e380 100644
--- a/superset-frontend/src/dashboard/components/PropertiesModal/index.tsx
+++ b/superset-frontend/src/dashboard/components/PropertiesModal/index.tsx
@@ -681,7 +681,7 @@ const PropertiesModal = ({
         </Row>
         <Row gutter={16}>
           <Col xs={24} md={12}>
-            <FormItem label={t('Title')} name="title">
+            <FormItem label={t('Name')} name="title">
               <Input
                 data-test="dashboard-title-input"
                 type="text"
diff --git a/superset-frontend/src/features/annotations/AnnotationModal.tsx b/superset-frontend/src/features/annotations/AnnotationModal.tsx
index a5c5aa9c31..dd1107dfba 100644
--- a/superset-frontend/src/features/annotations/AnnotationModal.tsx
+++ b/superset-frontend/src/features/annotations/AnnotationModal.tsx
@@ -287,7 +287,7 @@ const AnnotationModal: FunctionComponent<AnnotationModalProps> = ({
       </StyledAnnotationTitle>
       <AnnotationContainer>
         <div className="control-label">
-          {t('Annotation name')}
+          {t('Name')}
           <span className="required">*</span>
         </div>
         <input
diff --git a/superset-frontend/src/features/cssTemplates/CssTemplateModal.tsx b/superset-frontend/src/features/cssTemplates/CssTemplateModal.tsx
index 73bbfe7555..bd3c5b13a6 100644
--- a/superset-frontend/src/features/cssTemplates/CssTemplateModal.tsx
+++ b/superset-frontend/src/features/cssTemplates/CssTemplateModal.tsx
@@ -105,6 +105,9 @@ const CssTemplateModal: FunctionComponent<CssTemplateModalProps> = ({
         const update_id = currentCssTemplate.id;
         delete currentCssTemplate.id;
         delete currentCssTemplate.created_by;
+        delete currentCssTemplate.changed_by;
+        delete currentCssTemplate.changed_on_delta_humanized;
+
         updateResource(update_id, currentCssTemplate).then(response => {
           if (!response) {
             return;
@@ -235,7 +238,7 @@ const CssTemplateModal: FunctionComponent<CssTemplateModalProps> = ({
       </StyledCssTemplateTitle>
       <TemplateContainer>
         <div className="control-label">
-          {t('CSS template name')}
+          {t('Name')}
           <span className="required">*</span>
         </div>
         <input
diff --git a/superset-frontend/src/features/cssTemplates/types.ts b/superset-frontend/src/features/cssTemplates/types.ts
index 1bb5b2e659..5e7e1af97a 100644
--- a/superset-frontend/src/features/cssTemplates/types.ts
+++ b/superset-frontend/src/features/cssTemplates/types.ts
@@ -1,3 +1,5 @@
+import Owner from 'src/types/Owner';
+
 /**
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -16,17 +18,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-type CreatedByUser = {
-  id: number;
-  first_name: string;
-  last_name: string;
-};
-
 export type TemplateObject = {
   id?: number;
   changed_on_delta_humanized?: string;
   created_on?: string;
-  created_by?: CreatedByUser;
+  changed_by?: Owner;
+  created_by?: Owner;
   css?: string;
   template_name: string;
 };
diff --git a/superset-frontend/src/features/tags/TagModal.test.tsx b/superset-frontend/src/features/tags/TagModal.test.tsx
index 5f4fd4e2b9..99b7a3365e 100644
--- a/superset-frontend/src/features/tags/TagModal.test.tsx
+++ b/superset-frontend/src/features/tags/TagModal.test.tsx
@@ -56,10 +56,12 @@ test('renders correctly in edit mode', () => {
     changed_on_delta_humanized: '',
     created_on_delta_humanized: '',
     created_by: {
+      id: 1,
       first_name: 'joe',
       last_name: 'smith',
     },
     changed_by: {
+      id: 2,
       first_name: 'tom',
       last_name: 'brown',
     },
diff --git a/superset-frontend/src/pages/AlertReportList/index.tsx b/superset-frontend/src/pages/AlertReportList/index.tsx
index b0cd0a4622..c6d14d186f 100644
--- a/superset-frontend/src/pages/AlertReportList/index.tsx
+++ b/superset-frontend/src/pages/AlertReportList/index.tsx
@@ -53,6 +53,8 @@ import { isUserAdmin } from 'src/dashboard/util/permissionUtils';
 import Owner from 'src/types/Owner';
 import AlertReportModal from 'src/features/alerts/AlertReportModal';
 import { AlertObject, AlertState } from 'src/features/alerts/types';
+import { ModifiedInfo } from 'src/components/AuditInfo';
+import { QueryObjectColumns } from 'src/views/CRUD/types';
 
 const extensionsRegistry = getExtensionsRegistry();
 
@@ -303,18 +305,6 @@ function AlertList({
         disableSortBy: true,
         size: 'xl',
       },
-      {
-        Cell: ({
-          row: {
-            original: { created_by },
-          },
-        }: any) =>
-          created_by ? `${created_by.first_name} ${created_by.last_name}` : '',
-        Header: t('Created by'),
-        id: 'created_by',
-        disableSortBy: true,
-        size: 'xl',
-      },
       {
         Cell: ({
           row: {
@@ -329,10 +319,13 @@ function AlertList({
       {
         Cell: ({
           row: {
-            original: { changed_on_delta_humanized: changedOn },
+            original: {
+              changed_on_delta_humanized: changedOn,
+              changed_by: changedBy,
+            },
           },
-        }: any) => <span className="no-wrap">{changedOn}</span>,
-        Header: t('Modified'),
+        }: any) => <ModifiedInfo date={changedOn} user={changedBy} />,
+        Header: t('Last modified'),
         accessor: 'changed_on_delta_humanized',
         size: 'xl',
       },
@@ -407,6 +400,10 @@ function AlertList({
         disableSortBy: true,
         size: 'xl',
       },
+      {
+        accessor: QueryObjectColumns.changed_by,
+        hidden: true,
+      },
     ],
     [canDelete, canEdit, isReportEnabled, toggleActive],
   );
@@ -448,6 +445,13 @@ function AlertList({
 
   const filters: Filters = useMemo(
     () => [
+      {
+        Header: t('Name'),
+        key: 'search',
+        id: 'name',
+        input: 'search',
+        operator: FilterOperator.contains,
+      },
       {
         Header: t('Owner'),
         key: 'owner',
@@ -465,23 +469,6 @@ function AlertList({
         ),
         paginate: true,
       },
-      {
-        Header: t('Created by'),
-        key: 'created_by',
-        id: 'created_by',
-        input: 'select',
-        operator: FilterOperator.relationOneMany,
-        unfilteredLabel: 'All',
-        fetchSelects: createFetchRelated(
-          'report',
-          'created_by',
-          createErrorHandler(errMsg =>
-            t('An error occurred while fetching created by values: %s', errMsg),
-          ),
-          user,
-        ),
-        paginate: true,
-      },
       {
         Header: t('Status'),
         key: 'status',
@@ -504,11 +491,24 @@ function AlertList({
         ],
       },
       {
-        Header: t('Search'),
-        key: 'search',
-        id: 'name',
-        input: 'search',
-        operator: FilterOperator.contains,
+        Header: t('Modified by'),
+        key: 'changed_by',
+        id: 'changed_by',
+        input: 'select',
+        operator: FilterOperator.relationOneMany,
+        unfilteredLabel: t('All'),
+        fetchSelects: createFetchRelated(
+          'report',
+          'changed_by',
+          createErrorHandler(errMsg =>
+            t(
+              'An error occurred while fetching dataset datasource values: %s',
+              errMsg,
+            ),
+          ),
+          user,
+        ),
+        paginate: true,
       },
     ],
     [],
diff --git a/superset-frontend/src/pages/AllEntities/index.tsx b/superset-frontend/src/pages/AllEntities/index.tsx
index a1e2c52fe4..b94cab846d 100644
--- a/superset-frontend/src/pages/AllEntities/index.tsx
+++ b/superset-frontend/src/pages/AllEntities/index.tsx
@@ -35,6 +35,7 @@ import TagModal from 'src/features/tags/TagModal';
 import withToasts, { useToasts } from 'src/components/MessageToasts/withToasts';
 import { fetchObjectsByTagIds, fetchSingleTag } from 'src/features/tags/tags';
 import Loading from 'src/components/Loading';
+import getOwnerName from 'src/utils/getOwnerName';
 
 interface TaggedObject {
   id: number;
@@ -132,7 +133,7 @@ function AllEntities() {
 
   const owner: Owner = {
     type: MetadataType.OWNER,
-    createdBy: `${tag?.created_by.first_name} ${tag?.created_by.last_name}`,
+    createdBy: getOwnerName(tag?.created_by),
     createdOn: tag?.created_on_delta_humanized || '',
   };
   items.push(owner);
@@ -140,7 +141,7 @@ function AllEntities() {
   const lastModified: LastModified = {
     type: MetadataType.LAST_MODIFIED,
     value: tag?.changed_on_delta_humanized || '',
-    modifiedBy: `${tag?.changed_by.first_name} ${tag?.changed_by.last_name}`,
+    modifiedBy: getOwnerName(tag?.changed_by),
   };
   items.push(lastModified);
 
diff --git a/superset-frontend/src/pages/AnnotationLayerList/index.tsx b/superset-frontend/src/pages/AnnotationLayerList/index.tsx
index fc909538c0..fff5743b5a 100644
--- a/superset-frontend/src/pages/AnnotationLayerList/index.tsx
+++ b/superset-frontend/src/pages/AnnotationLayerList/index.tsx
@@ -21,7 +21,6 @@ import React, { useMemo, useState } from 'react';
 import rison from 'rison';
 import { t, SupersetClient } from '@superset-ui/core';
 import { Link, useHistory } from 'react-router-dom';
-import moment from 'moment';
 import { useListViewResource } from 'src/views/CRUD/hooks';
 import { createFetchRelated, createErrorHandler } from 'src/views/CRUD/utils';
 import withToasts from 'src/components/MessageToasts/withToasts';
@@ -36,9 +35,10 @@ import DeleteModal from 'src/components/DeleteModal';
 import ConfirmStatusChange from 'src/components/ConfirmStatusChange';
 import AnnotationLayerModal from 'src/features/annotationLayers/AnnotationLayerModal';
 import { AnnotationLayerObject } from 'src/features/annotationLayers/types';
+import { ModifiedInfo } from 'src/components/AuditInfo';
+import { QueryObjectColumns } from 'src/views/CRUD/types';
 
 const PAGE_SIZE = 25;
-const MOMENT_FORMAT = 'MMM DD, YYYY';
 
 interface AnnotationLayersListProps {
   addDangerToast: (msg: string) => void;
@@ -156,65 +156,16 @@ function AnnotationLayersList({
       {
         Cell: ({
           row: {
-            original: { changed_on: changedOn },
+            original: {
+              changed_on_delta_humanized: changedOn,
+              changed_by: changedBy,
+            },
           },
-        }: any) => {
-          const date = new Date(changedOn);
-          const utc = new Date(
-            Date.UTC(
-              date.getFullYear(),
-              date.getMonth(),
-              date.getDate(),
-              date.getHours(),
-              date.getMinutes(),
-              date.getSeconds(),
-              date.getMilliseconds(),
-            ),
-          );
-
-          return moment(utc).format(MOMENT_FORMAT);
-        },
+        }: any) => <ModifiedInfo date={changedOn} user={changedBy} />,
         Header: t('Last modified'),
         accessor: 'changed_on',
         size: 'xl',
       },
-      {
-        Cell: ({
-          row: {
-            original: { created_on: createdOn },
-          },
-        }: any) => {
-          const date = new Date(createdOn);
-          const utc = new Date(
-            Date.UTC(
-              date.getFullYear(),
-              date.getMonth(),
-              date.getDate(),
-              date.getHours(),
-              date.getMinutes(),
-              date.getSeconds(),
-              date.getMilliseconds(),
-            ),
-          );
-
-          return moment(utc).format(MOMENT_FORMAT);
-        },
-        Header: t('Created on'),
-        accessor: 'created_on',
-        size: 'xl',
-      },
-      {
-        accessor: 'created_by',
-        disableSortBy: true,
-        Header: t('Created by'),
-        Cell: ({
-          row: {
-            original: { created_by: createdBy },
-          },
-        }: any) =>
-          createdBy ? `${createdBy.first_name} ${createdBy.last_name}` : '',
-        size: 'xl',
-      },
       {
         Cell: ({ row: { original } }: any) => {
           const handleEdit = () => handleAnnotationLayerEdit(original);
@@ -249,6 +200,10 @@ function AnnotationLayersList({
         hidden: !canEdit && !canDelete,
         size: 'xl',
       },
+      {
+        accessor: QueryObjectColumns.changed_by,
+        hidden: true,
+      },
     ],
     [canDelete, canCreate],
   );
@@ -280,15 +235,22 @@ function AnnotationLayersList({
   const filters: Filters = useMemo(
     () => [
       {
-        Header: t('Created by'),
-        key: 'created_by',
-        id: 'created_by',
+        Header: t('Name'),
+        key: 'search',
+        id: 'name',
+        input: 'search',
+        operator: FilterOperator.contains,
+      },
+      {
+        Header: t('Changed by'),
+        key: 'changed_by',
+        id: 'changed_by',
         input: 'select',
         operator: FilterOperator.relationOneMany,
         unfilteredLabel: t('All'),
         fetchSelects: createFetchRelated(
           'annotation_layer',
-          'created_by',
+          'changed_by',
           createErrorHandler(errMsg =>
             t(
               'An error occurred while fetching dataset datasource values: %s',
@@ -299,13 +261,6 @@ function AnnotationLayersList({
         ),
         paginate: true,
       },
-      {
-        Header: t('Search'),
-        key: 'search',
-        id: 'name',
-        input: 'search',
-        operator: FilterOperator.contains,
-      },
     ],
     [],
   );
diff --git a/superset-frontend/src/pages/AnnotationList/index.tsx b/superset-frontend/src/pages/AnnotationList/index.tsx
index 980a18ba72..e04b48080f 100644
--- a/superset-frontend/src/pages/AnnotationList/index.tsx
+++ b/superset-frontend/src/pages/AnnotationList/index.tsx
@@ -154,7 +154,7 @@ function AnnotationList({
     () => [
       {
         accessor: 'short_descr',
-        Header: t('Label'),
+        Header: t('Name'),
       },
       {
         accessor: 'long_descr',
diff --git a/superset-frontend/src/pages/ChartList/index.tsx b/superset-frontend/src/pages/ChartList/index.tsx
index d13113158e..5ed967d7c1 100644
--- a/superset-frontend/src/pages/ChartList/index.tsx
+++ b/superset-frontend/src/pages/ChartList/index.tsx
@@ -29,7 +29,6 @@ import {
 import React, { useState, useMemo, useCallback } from 'react';
 import rison from 'rison';
 import { uniqBy } from 'lodash';
-import moment from 'moment';
 import { useSelector } from 'react-redux';
 import {
   createErrorHandler,
@@ -69,11 +68,13 @@ import setupPlugins from 'src/setup/setupPlugins';
 import InfoTooltip from 'src/components/InfoTooltip';
 import CertifiedBadge from 'src/components/CertifiedBadge';
 import { GenericLink } from 'src/components/GenericLink/GenericLink';
-import Owner from 'src/types/Owner';
 import { loadTags } from 'src/components/Tags/utils';
+import FacePile from 'src/components/FacePile';
 import ChartCard from 'src/features/charts/ChartCard';
 import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes';
 import { findPermission } from 'src/utils/findPermission';
+import { ModifiedInfo } from 'src/components/AuditInfo';
+import { QueryObjectColumns } from 'src/views/CRUD/types';
 
 const FlexRowContainer = styled.div`
   align-items: center;
@@ -245,10 +246,6 @@ function ChartList(props: ChartListProps) {
     });
     setPreparingExport(true);
   };
-  const changedByName = (lastSavedBy: Owner) =>
-    lastSavedBy?.first_name
-      ? `${lastSavedBy?.first_name} ${lastSavedBy?.last_name}`
-      : null;
 
   function handleBulkChartDelete(chartsToDelete: Chart[]) {
     SupersetClient.delete({
@@ -366,7 +363,7 @@ function ChartList(props: ChartListProps) {
             )}
           </FlexRowContainer>
         ),
-        Header: t('Chart'),
+        Header: t('Name'),
         accessor: 'slice_name',
       },
       {
@@ -375,7 +372,7 @@ function ChartList(props: ChartListProps) {
             original: { viz_type: vizType },
           },
         }: any) => registry.get(vizType)?.name || vizType,
-        Header: t('Visualization type'),
+        Header: t('Type'),
         accessor: 'viz_type',
         size: 'xxl',
       },
@@ -438,44 +435,27 @@ function ChartList(props: ChartListProps) {
       {
         Cell: ({
           row: {
-            original: { last_saved_by: lastSavedBy },
+            original: { owners = [] },
           },
-        }: any) => <>{changedByName(lastSavedBy)}</>,
-        Header: t('Modified by'),
-        accessor: 'last_saved_by.first_name',
+        }: any) => <FacePile users={owners} />,
+        Header: t('Owners'),
+        accessor: 'owners',
+        disableSortBy: true,
         size: 'xl',
       },
       {
         Cell: ({
           row: {
-            original: { last_saved_at: lastSavedAt },
+            original: {
+              changed_on_delta_humanized: changedOn,
+              changed_by: changedBy,
+            },
           },
-        }: any) => (
-          <span className="no-wrap">
-            {lastSavedAt ? moment.utc(lastSavedAt).fromNow() : null}
-          </span>
-        ),
+        }: any) => <ModifiedInfo date={changedOn} user={changedBy} />,
         Header: t('Last modified'),
         accessor: 'last_saved_at',
         size: 'xl',
       },
-      {
-        accessor: 'owners',
-        hidden: true,
-        disableSortBy: true,
-      },
-      {
-        Cell: ({
-          row: {
-            original: { created_by: createdBy },
-          },
-        }: any) =>
-          createdBy ? `${createdBy.first_name} ${createdBy.last_name}` : '',
-        Header: t('Created by'),
-        accessor: 'created_by',
-        disableSortBy: true,
-        size: 'xl',
-      },
       {
         Cell: ({ row: { original } }: any) => {
           const handleDelete = () =>
@@ -563,6 +543,10 @@ function ChartList(props: ChartListProps) {
         disableSortBy: true,
         hidden: !canEdit && !canDelete,
       },
+      {
+        accessor: QueryObjectColumns.changed_by,
+        hidden: true,
+      },
     ],
     [
       userId,
@@ -597,58 +581,14 @@ function ChartList(props: ChartListProps) {
   const filters: Filters = useMemo(() => {
     const filters_list = [
       {
-        Header: t('Search'),
+        Header: t('Name'),
         key: 'search',
         id: 'slice_name',
         input: 'search',
         operator: FilterOperator.chartAllText,
       },
       {
-        Header: t('Owner'),
-        key: 'owner',
-        id: 'owners',
-        input: 'select',
-        operator: FilterOperator.relationManyMany,
-        unfilteredLabel: t('All'),
-        fetchSelects: createFetchRelated(
-          'chart',
-          'owners',
-          createErrorHandler(errMsg =>
-            addDangerToast(
-              t(
-                'An error occurred while fetching chart owners values: %s',
-                errMsg,
-              ),
-            ),
-          ),
-          props.user,
-        ),
-        paginate: true,
-      },
-      {
-        Header: t('Created by'),
-        key: 'created_by',
-        id: 'created_by',
-        input: 'select',
-        operator: FilterOperator.relationOneMany,
-        unfilteredLabel: t('All'),
-        fetchSelects: createFetchRelated(
-          'chart',
-          'created_by',
-          createErrorHandler(errMsg =>
-            addDangerToast(
-              t(
-                'An error occurred while fetching chart created by values: %s',
-                errMsg,
-              ),
-            ),
-          ),
-          props.user,
-        ),
-        paginate: true,
-      },
-      {
-        Header: t('Chart type'),
+        Header: t('Type'),
         key: 'viz_type',
         id: 'viz_type',
         input: 'select',
@@ -683,8 +623,43 @@ function ChartList(props: ChartListProps) {
         fetchSelects: createFetchDatasets,
         paginate: true,
       },
+      ...(isFeatureEnabled(FeatureFlag.TAGGING_SYSTEM) && canReadTag
+        ? [
+            {
+              Header: t('Tag'),
+              key: 'tags',
+              id: 'tags',
+              input: 'select',
+              operator: FilterOperator.chartTags,
+              unfilteredLabel: t('All'),
+              fetchSelects: loadTags,
+            },
+          ]
+        : []),
       {
-        Header: t('Dashboards'),
+        Header: t('Owner'),
+        key: 'owner',
+        id: 'owners',
+        input: 'select',
+        operator: FilterOperator.relationManyMany,
+        unfilteredLabel: t('All'),
+        fetchSelects: createFetchRelated(
+          'chart',
+          'owners',
+          createErrorHandler(errMsg =>
+            addDangerToast(
+              t(
+                'An error occurred while fetching chart owners values: %s',
+                errMsg,
+              ),
+            ),
+          ),
+          props.user,
+        ),
+        paginate: true,
+      },
+      {
+        Header: t('Dashboard'),
         key: 'dashboards',
         id: 'dashboards',
         input: 'select',
@@ -707,18 +682,27 @@ function ChartList(props: ChartListProps) {
           { label: t('No'), value: false },
         ],
       },
-    ] as Filters;
-    if (isFeatureEnabled(FeatureFlag.TAGGING_SYSTEM) && canReadTag) {
-      filters_list.push({
-        Header: t('Tags'),
-        key: 'tags',
-        id: 'tags',
+      {
+        Header: t('Modified by'),
+        key: 'changed_by',
+        id: 'changed_by',
         input: 'select',
-        operator: FilterOperator.chartTags,
+        operator: FilterOperator.relationOneMany,
         unfilteredLabel: t('All'),
-        fetchSelects: loadTags,
-      });
-    }
+        fetchSelects: createFetchRelated(
+          'chart',
+          'changed_by',
+          createErrorHandler(errMsg =>
+            t(
+              'An error occurred while fetching dataset datasource values: %s',
+              errMsg,
+            ),
+          ),
+          props.user,
+        ),
+        paginate: true,
+      },
+    ] as Filters;
     return filters_list;
   }, [addDangerToast, favoritesFilter, props.user]);
 
diff --git a/superset-frontend/src/pages/CssTemplateList/index.tsx b/superset-frontend/src/pages/CssTemplateList/index.tsx
index f777f8e743..b77217b22f 100644
--- a/superset-frontend/src/pages/CssTemplateList/index.tsx
+++ b/superset-frontend/src/pages/CssTemplateList/index.tsx
@@ -21,13 +21,11 @@ import React, { useMemo, useState } from 'react';
 import { t, SupersetClient } from '@superset-ui/core';
 
 import rison from 'rison';
-import moment from 'moment';
 import { useListViewResource } from 'src/views/CRUD/hooks';
-import { createFetchRelated, createErrorHandler } from 'src/views/CRUD/utils';
+import { createErrorHandler, createFetchRelated } from 'src/views/CRUD/utils';
 import withToasts from 'src/components/MessageToasts/withToasts';
 import SubMenu, { SubMenuProps } from 'src/features/home/SubMenu';
 import DeleteModal from 'src/components/DeleteModal';
-import { Tooltip } from 'src/components/Tooltip';
 import ConfirmStatusChange from 'src/components/ConfirmStatusChange';
 import ActionsBar, { ActionProps } from 'src/components/ListView/ActionsBar';
 import ListView, {
@@ -37,6 +35,8 @@ import ListView, {
 } from 'src/components/ListView';
 import CssTemplateModal from 'src/features/cssTemplates/CssTemplateModal';
 import { TemplateObject } from 'src/features/cssTemplates/types';
+import { ModifiedInfo } from 'src/components/AuditInfo';
+import { QueryObjectColumns } from 'src/views/CRUD/types';
 
 const PAGE_SIZE = 25;
 
@@ -138,66 +138,12 @@ function CssTemplatesList({
               changed_by: changedBy,
             },
           },
-        }: any) => {
-          let name = 'null';
-
-          if (changedBy) {
-            name = `${changedBy.first_name} ${changedBy.last_name}`;
-          }
-
-          return (
-            <Tooltip
-              id="allow-run-async-header-tooltip"
-              title={t('Last modified by %s', name)}
-              placement="right"
-            >
-              <span>{changedOn}</span>
-            </Tooltip>
-          );
-        },
+        }: any) => <ModifiedInfo date={changedOn} user={changedBy} />,
         Header: t('Last modified'),
         accessor: 'changed_on_delta_humanized',
         size: 'xl',
         disableSortBy: true,
       },
-      {
-        Cell: ({
-          row: {
-            original: { created_on: createdOn },
-          },
-        }: any) => {
-          const date = new Date(createdOn);
-          const utc = new Date(
-            Date.UTC(
-              date.getFullYear(),
-              date.getMonth(),
-              date.getDate(),
-              date.getHours(),
-              date.getMinutes(),
-              date.getSeconds(),
-              date.getMilliseconds(),
-            ),
-          );
-
-          return moment(utc).fromNow();
-        },
-        Header: t('Created on'),
-        accessor: 'created_on',
-        size: 'xl',
-        disableSortBy: true,
-      },
-      {
-        accessor: 'created_by',
-        disableSortBy: true,
-        Header: t('Created by'),
-        Cell: ({
-          row: {
-            original: { created_by: createdBy },
-          },
-        }: any) =>
-          createdBy ? `${createdBy.first_name} ${createdBy.last_name}` : '',
-        size: 'xl',
-      },
       {
         Cell: ({ row: { original } }: any) => {
           const handleEdit = () => handleCssTemplateEdit(original);
@@ -232,6 +178,10 @@ function CssTemplatesList({
         hidden: !canEdit && !canDelete,
         size: 'xl',
       },
+      {
+        accessor: QueryObjectColumns.changed_by,
+        hidden: true,
+      },
     ],
     [canDelete, canCreate],
   );
@@ -270,15 +220,22 @@ function CssTemplatesList({
   const filters: Filters = useMemo(
     () => [
       {
-        Header: t('Created by'),
-        key: 'created_by',
-        id: 'created_by',
+        Header: t('Name'),
+        key: 'search',
+        id: 'template_name',
+        input: 'search',
+        operator: FilterOperator.contains,
+      },
+      {
+        Header: t('Modified by'),
+        key: 'changed_by',
+        id: 'changed_by',
         input: 'select',
         operator: FilterOperator.relationOneMany,
         unfilteredLabel: t('All'),
         fetchSelects: createFetchRelated(
           'css_template',
-          'created_by',
+          'changed_by',
           createErrorHandler(errMsg =>
             t(
               'An error occurred while fetching dataset datasource values: %s',
@@ -289,13 +246,6 @@ function CssTemplatesList({
         ),
         paginate: true,
       },
-      {
-        Header: t('Search'),
-        key: 'search',
-        id: 'template_name',
-        input: 'search',
-        operator: FilterOperator.contains,
-      },
     ],
     [],
   );
diff --git a/superset-frontend/src/pages/DashboardList/index.tsx b/superset-frontend/src/pages/DashboardList/index.tsx
index 6542d85129..e82b701859 100644
--- a/superset-frontend/src/pages/DashboardList/index.tsx
+++ b/superset-frontend/src/pages/DashboardList/index.tsx
@@ -57,13 +57,17 @@ import { Tooltip } from 'src/components/Tooltip';
 import ImportModelsModal from 'src/components/ImportModal/index';
 
 import Dashboard from 'src/dashboard/containers/Dashboard';
-import { Dashboard as CRUDDashboard } from 'src/views/CRUD/types';
+import {
+  Dashboard as CRUDDashboard,
+  QueryObjectColumns,
+} from 'src/views/CRUD/types';
 import CertifiedBadge from 'src/components/CertifiedBadge';
 import { loadTags } from 'src/components/Tags/utils';
 import DashboardCard from 'src/features/dashboards/DashboardCard';
 import { DashboardStatus } from 'src/features/dashboards/types';
 import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes';
 import { findPermission } from 'src/utils/findPermission';
+import { ModifiedInfo } from 'src/components/AuditInfo';
 
 const PAGE_SIZE = 25;
 const PASSWORDS_NEEDED_MESSAGE = t(
@@ -108,11 +112,7 @@ const Actions = styled.div`
 `;
 
 function DashboardList(props: DashboardListProps) {
-  const {
-    addDangerToast,
-    addSuccessToast,
-    user: { userId },
-  } = props;
+  const { addDangerToast, addSuccessToast, user } = props;
 
   const { roles } = useSelector<any, UserWithPermissionsAndRoles>(
     state => state.user,
@@ -178,7 +178,7 @@ function DashboardList(props: DashboardListProps) {
   };
 
   // TODO: Fix usage of localStorage keying on the user id
-  const userKey = dangerouslyGetItemDoNotUse(userId?.toString(), null);
+  const userKey = dangerouslyGetItemDoNotUse(user?.userId?.toString(), null);
 
   const canCreate = hasPerm('can_write');
   const canEdit = hasPerm('can_write');
@@ -274,7 +274,7 @@ function DashboardList(props: DashboardListProps) {
             original: { id },
           },
         }: any) =>
-          userId && (
+          user?.userId && (
             <FaveStar
               itemId={id}
               saveFaveStar={saveFavoriteStatus}
@@ -285,7 +285,7 @@ function DashboardList(props: DashboardListProps) {
         id: 'id',
         disableSortBy: true,
         size: 'xs',
-        hidden: !userId,
+        hidden: !user?.userId,
       },
       {
         Cell: ({
@@ -310,9 +310,20 @@ function DashboardList(props: DashboardListProps) {
             {dashboardTitle}
           </Link>
         ),
-        Header: t('Title'),
+        Header: t('Name'),
         accessor: 'dashboard_title',
       },
+      {
+        Cell: ({
+          row: {
+            original: { status },
+          },
+        }: any) =>
+          status === DashboardStatus.PUBLISHED ? t('Published') : t('Draft'),
+        Header: t('Status'),
+        accessor: 'published',
+        size: 'xl',
+      },
       {
         Cell: ({
           row: {
@@ -341,55 +352,25 @@ function DashboardList(props: DashboardListProps) {
       {
         Cell: ({
           row: {
-            original: { changed_by_name: changedByName },
-          },
-        }: any) => <>{changedByName}</>,
-        Header: t('Modified by'),
-        accessor: 'changed_by.first_name',
-        size: 'xl',
-      },
-      {
-        Cell: ({
-          row: {
-            original: { status },
-          },
-        }: any) =>
-          status === DashboardStatus.PUBLISHED ? t('Published') : t('Draft'),
-        Header: t('Status'),
-        accessor: 'published',
-        size: 'xl',
-      },
-      {
-        Cell: ({
-          row: {
-            original: { changed_on_delta_humanized: changedOn },
-          },
-        }: any) => <span className="no-wrap">{changedOn}</span>,
-        Header: t('Modified'),
-        accessor: 'changed_on_delta_humanized',
-        size: 'xl',
-      },
-      {
-        Cell: ({
-          row: {
-            original: { created_by: createdBy },
+            original: { owners = [] },
           },
-        }: any) =>
-          createdBy ? `${createdBy.first_name} ${createdBy.last_name}` : '',
-        Header: t('Created by'),
-        accessor: 'created_by',
+        }: any) => <FacePile users={owners} />,
+        Header: t('Owners'),
+        accessor: 'owners',
         disableSortBy: true,
         size: 'xl',
       },
       {
         Cell: ({
           row: {
-            original: { owners = [] },
+            original: {
+              changed_on_delta_humanized: changedOn,
+              changed_by: changedBy,
+            },
           },
-        }: any) => <FacePile users={owners} />,
-        Header: t('Owners'),
-        accessor: 'owners',
-        disableSortBy: true,
+        }: any) => <ModifiedInfo date={changedOn} user={changedBy} />,
+        Header: t('Last modified'),
+        accessor: 'changed_on_delta_humanized',
         size: 'xl',
       },
       {
@@ -475,9 +456,13 @@ function DashboardList(props: DashboardListProps) {
         hidden: !canEdit && !canDelete && !canExport,
         disableSortBy: true,
       },
+      {
+        accessor: QueryObjectColumns.changed_by,
+        hidden: true,
+      },
     ],
     [
-      userId,
+      user?.userId,
       canEdit,
       canDelete,
       canExport,
@@ -509,12 +494,37 @@ function DashboardList(props: DashboardListProps) {
   const filters: Filters = useMemo(() => {
     const filters_list = [
       {
-        Header: t('Search'),
+        Header: t('Name'),
         key: 'search',
         id: 'dashboard_title',
         input: 'search',
         operator: FilterOperator.titleOrSlug,
       },
+      {
+        Header: t('Status'),
+        key: 'published',
+        id: 'published',
+        input: 'select',
+        operator: FilterOperator.equals,
+        unfilteredLabel: t('Any'),
+        selects: [
+          { label: t('Published'), value: true },
+          { label: t('Draft'), value: false },
+        ],
+      },
+      ...(isFeatureEnabled(FeatureFlag.TAGGING_SYSTEM) && canReadTag
+        ? [
+            {
+              Header: t('Tag'),
+              key: 'tags',
+              id: 'tags',
+              input: 'select',
+              operator: FilterOperator.dashboardTags,
+              unfilteredLabel: t('All'),
+              fetchSelects: loadTags,
+            },
+          ]
+        : []),
       {
         Header: t('Owner'),
         key: 'owner',
@@ -537,41 +547,7 @@ function DashboardList(props: DashboardListProps) {
         ),
         paginate: true,
       },
-      {
-        Header: t('Created by'),
-        key: 'created_by',
-        id: 'created_by',
-        input: 'select',
-        operator: FilterOperator.relationOneMany,
-        unfilteredLabel: t('All'),
-        fetchSelects: createFetchRelated(
-          'dashboard',
-          'created_by',
-          createErrorHandler(errMsg =>
-            addDangerToast(
-              t(
-                'An error occurred while fetching dashboard created by values: %s',
-                errMsg,
-              ),
-            ),
-          ),
-          props.user,
-        ),
-        paginate: true,
-      },
-      {
-        Header: t('Status'),
-        key: 'published',
-        id: 'published',
-        input: 'select',
-        operator: FilterOperator.equals,
-        unfilteredLabel: t('Any'),
-        selects: [
-          { label: t('Published'), value: true },
-          { label: t('Draft'), value: false },
-        ],
-      },
-      ...(userId ? [favoritesFilter] : []),
+      ...(user?.userId ? [favoritesFilter] : []),
       {
         Header: t('Certified'),
         key: 'certified',
@@ -585,18 +561,27 @@ function DashboardList(props: DashboardListProps) {
           { label: t('No'), value: false },
         ],
       },
-    ] as Filters;
-    if (isFeatureEnabled(FeatureFlag.TAGGING_SYSTEM) && canReadTag) {
-      filters_list.push({
-        Header: t('Tags'),
-        key: 'tags',
-        id: 'tags',
+      {
+        Header: t('Modified by'),
+        key: 'changed_by',
+        id: 'changed_by',
         input: 'select',
-        operator: FilterOperator.dashboardTags,
+        operator: FilterOperator.relationOneMany,
         unfilteredLabel: t('All'),
-        fetchSelects: loadTags,
-      });
-    }
+        fetchSelects: createFetchRelated(
+          'dashboard',
+          'changed_by',
+          createErrorHandler(errMsg =>
+            t(
+              'An error occurred while fetching dataset datasource values: %s',
+              errMsg,
+            ),
+          ),
+          user,
+        ),
+        paginate: true,
+      },
+    ] as Filters;
     return filters_list;
   }, [addDangerToast, favoritesFilter, props.user]);
 
@@ -632,7 +617,7 @@ function DashboardList(props: DashboardListProps) {
             ? userKey.thumbnails
             : isFeatureEnabled(FeatureFlag.THUMBNAILS)
         }
-        userId={userId}
+        userId={user?.userId}
         loading={loading}
         openDashboardEditModal={openDashboardEditModal}
         saveFavoriteStatus={saveFavoriteStatus}
@@ -646,7 +631,7 @@ function DashboardList(props: DashboardListProps) {
       favoriteStatus,
       hasPerm,
       loading,
-      userId,
+      user?.userId,
       saveFavoriteStatus,
       userKey,
     ],
@@ -743,7 +728,7 @@ function DashboardList(props: DashboardListProps) {
                       addSuccessToast,
                       addDangerToast,
                       undefined,
-                      userId,
+                      user?.userId,
                     );
                     setDashboardToDelete(null);
                   }}
diff --git a/superset-frontend/src/pages/DatabaseList/DatabaseList.test.jsx b/superset-frontend/src/pages/DatabaseList/DatabaseList.test.jsx
index fd989b50d2..b1bfb245d3 100644
--- a/superset-frontend/src/pages/DatabaseList/DatabaseList.test.jsx
+++ b/superset-frontend/src/pages/DatabaseList/DatabaseList.test.jsx
@@ -218,7 +218,7 @@ describe('Admin DatabaseList', () => {
     await waitForComponentToPaint(wrapper);
 
     expect(fetchMock.lastCall()[0]).toMatchInlineSnapshot(
-      `"http://localhost/api/v1/database/?q=(filters:!((col:expose_in_sqllab,opr:eq,value:!t),(col:allow_run_async,opr:eq,value:!f),(col:database_name,opr:ct,value:fooo)),order_column:changed_on_delta_humanized,order_direction:desc,page:0,page_size:25)"`,
+      `"http://localhost/api/v1/database/?q=(filters:!((col:database_name,opr:ct,value:fooo),(col:expose_in_sqllab,opr:eq,value:!t),(col:allow_run_async,opr:eq,value:!f)),order_column:changed_on_delta_humanized,order_direction:desc,page:0,page_size:25)"`,
     );
   });
 
diff --git a/superset-frontend/src/pages/DatabaseList/index.tsx b/superset-frontend/src/pages/DatabaseList/index.tsx
index d2308bd117..8c98392aca 100644
--- a/superset-frontend/src/pages/DatabaseList/index.tsx
+++ b/superset-frontend/src/pages/DatabaseList/index.tsx
@@ -32,7 +32,11 @@ import { LocalStorageKeys, setItem } from 'src/utils/localStorageHelpers';
 
 import Loading from 'src/components/Loading';
 import { useListViewResource } from 'src/views/CRUD/hooks';
-import { createErrorHandler, uploadUserPerms } from 'src/views/CRUD/utils';
+import {
+  createErrorHandler,
+  createFetchRelated,
+  uploadUserPerms,
+} from 'src/views/CRUD/utils';
 import withToasts from 'src/components/MessageToasts/withToasts';
 import SubMenu, { SubMenuProps } from 'src/features/home/SubMenu';
 import DeleteModal from 'src/components/DeleteModal';
@@ -48,6 +52,8 @@ import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes';
 import type { MenuObjectProps } from 'src/types/bootstrapTypes';
 import DatabaseModal from 'src/features/databases/DatabaseModal';
 import { DatabaseObject } from 'src/features/databases/types';
+import { ModifiedInfo } from 'src/components/AuditInfo';
+import { QueryObjectColumns } from 'src/views/CRUD/types';
 
 const extensionsRegistry = getExtensionsRegistry();
 const DatabaseDeleteRelatedExtension = extensionsRegistry.get(
@@ -67,6 +73,11 @@ interface DatabaseDeleteObject extends DatabaseObject {
 interface DatabaseListProps {
   addDangerToast: (msg: string) => void;
   addSuccessToast: (msg: string) => void;
+  user: {
+    userId: string | number;
+    firstName: string;
+    lastName: string;
+  };
 }
 
 const IconCheck = styled(Icons.Check)`
@@ -90,7 +101,11 @@ function BooleanDisplay({ value }: { value: Boolean }) {
   return value ? <IconCheck /> : <IconCancelX />;
 }
 
-function DatabaseList({ addDangerToast, addSuccessToast }: DatabaseListProps) {
+function DatabaseList({
+  addDangerToast,
+  addSuccessToast,
+  user,
+}: DatabaseListProps) {
   const {
     state: {
       loading,
@@ -105,7 +120,7 @@ function DatabaseList({ addDangerToast, addSuccessToast }: DatabaseListProps) {
     t('database'),
     addDangerToast,
   );
-  const user = useSelector<any, UserWithPermissionsAndRoles>(
+  const fullUser = useSelector<any, UserWithPermissionsAndRoles>(
     state => state.user,
   );
   const showDatabaseModal = getUrlParam(URL_PARAMS.showDatabaseModal);
@@ -123,11 +138,11 @@ function DatabaseList({ addDangerToast, addSuccessToast }: DatabaseListProps) {
     null,
   );
   const [allowUploads, setAllowUploads] = useState<boolean>(false);
-  const isAdmin = isUserAdmin(user);
+  const isAdmin = isUserAdmin(fullUser);
   const showUploads = allowUploads || isAdmin;
 
   const [preparingExport, setPreparingExport] = useState<boolean>(false);
-  const { roles } = user;
+  const { roles } = fullUser;
   const {
     CSV_EXTENSIONS,
     COLUMNAR_EXTENSIONS,
@@ -313,7 +328,7 @@ function DatabaseList({ addDangerToast, addSuccessToast }: DatabaseListProps) {
     () => [
       {
         accessor: 'database_name',
-        Header: t('Database'),
+        Header: t('Name'),
       },
       {
         accessor: 'backend',
@@ -380,23 +395,14 @@ function DatabaseList({ addDangerToast, addSuccessToast }: DatabaseListProps) {
         size: 'md',
       },
       {
-        accessor: 'created_by',
-        disableSortBy: true,
-        Header: t('Created by'),
         Cell: ({
           row: {
-            original: { created_by: createdBy },
+            original: {
+              changed_by: changedBy,
+              changed_on_delta_humanized: changedOn,
+            },
           },
-        }: any) =>
-          createdBy ? `${createdBy.first_name} ${createdBy.last_name}` : '',
-        size: 'xl',
-      },
-      {
-        Cell: ({
-          row: {
-            original: { changed_on_delta_humanized: changedOn },
-          },
-        }: any) => changedOn,
+        }: any) => <ModifiedInfo date={changedOn} user={changedBy} />,
         Header: t('Last modified'),
         accessor: 'changed_on_delta_humanized',
         size: 'xl',
@@ -470,12 +476,23 @@ function DatabaseList({ addDangerToast, addSuccessToast }: DatabaseListProps) {
         hidden: !canEdit && !canDelete,
         disableSortBy: true,
       },
+      {
+        accessor: QueryObjectColumns.changed_by,
+        hidden: true,
+      },
     ],
     [canDelete, canEdit, canExport],
   );
 
   const filters: Filters = useMemo(
     () => [
+      {
+        Header: t('Name'),
+        key: 'search',
+        id: 'database_name',
+        input: 'search',
+        operator: FilterOperator.contains,
+      },
       {
         Header: t('Expose in SQL Lab'),
         key: 'expose_in_sql_lab',
@@ -509,11 +526,24 @@ function DatabaseList({ addDangerToast, addSuccessToast }: DatabaseListProps) {
         ],
       },
       {
-        Header: t('Search'),
-        key: 'search',
-        id: 'database_name',
-        input: 'search',
-        operator: FilterOperator.contains,
+        Header: t('Modified by'),
+        key: 'changed_by',
+        id: 'changed_by',
+        input: 'select',
+        operator: FilterOperator.relationOneMany,
+        unfilteredLabel: t('All'),
+        fetchSelects: createFetchRelated(
+          'database',
+          'changed_by',
+          createErrorHandler(errMsg =>
+            t(
+              'An error occurred while fetching dataset datasource values: %s',
+              errMsg,
+            ),
+          ),
+          user,
+        ),
+        paginate: true,
       },
     ],
     [],
diff --git a/superset-frontend/src/pages/DatasetList/DatasetList.test.tsx b/superset-frontend/src/pages/DatasetList/DatasetList.test.tsx
index 916dd0615b..c316001bb4 100644
--- a/superset-frontend/src/pages/DatasetList/DatasetList.test.tsx
+++ b/superset-frontend/src/pages/DatasetList/DatasetList.test.tsx
@@ -285,56 +285,41 @@ describe('RTL', () => {
 });
 
 describe('Prevent unsafe URLs', () => {
+  const columnCount = 8;
+  const exploreUrlIndex = 1;
+  const getTdIndex = (rowNumber: number): number =>
+    rowNumber * columnCount + exploreUrlIndex;
+
   const mockedProps = {};
   let wrapper: any;
 
   it('Check prevent unsafe is on renders relative links', async () => {
-    const tdColumnsNumber = 9;
     useSelectorMock.mockReturnValue(true);
     wrapper = await mountAndWait(mockedProps);
     const tdElements = wrapper.find(ListView).find('td');
-    expect(
-      tdElements
-        .at(0 * tdColumnsNumber + 1)
-        .find('a')
-        .prop('href'),
-    ).toBe('/https://www.google.com?0');
-    expect(
-      tdElements
-        .at(1 * tdColumnsNumber + 1)
-        .find('a')
-        .prop('href'),
-    ).toBe('/https://www.google.com?1');
-    expect(
-      tdElements
-        .at(2 * tdColumnsNumber + 1)
-        .find('a')
-        .prop('href'),
-    ).toBe('/https://www.google.com?2');
+    expect(tdElements.at(getTdIndex(0)).find('a').prop('href')).toBe(
+      '/https://www.google.com?0',
+    );
+    expect(tdElements.at(getTdIndex(1)).find('a').prop('href')).toBe(
+      '/https://www.google.com?1',
+    );
+    expect(tdElements.at(getTdIndex(2)).find('a').prop('href')).toBe(
+      '/https://www.google.com?2',
+    );
   });
 
   it('Check prevent unsafe is off renders absolute links', async () => {
-    const tdColumnsNumber = 9;
     useSelectorMock.mockReturnValue(false);
     wrapper = await mountAndWait(mockedProps);
     const tdElements = wrapper.find(ListView).find('td');
-    expect(
-      tdElements
-        .at(0 * tdColumnsNumber + 1)
-        .find('a')
-        .prop('href'),
-    ).toBe('https://www.google.com?0');
-    expect(
-      tdElements
-        .at(1 * tdColumnsNumber + 1)
-        .find('a')
-        .prop('href'),
-    ).toBe('https://www.google.com?1');
-    expect(
-      tdElements
-        .at(2 * tdColumnsNumber + 1)
-        .find('a')
-        .prop('href'),
-    ).toBe('https://www.google.com?2');
+    expect(tdElements.at(getTdIndex(0)).find('a').prop('href')).toBe(
+      'https://www.google.com?0',
+    );
+    expect(tdElements.at(getTdIndex(1)).find('a').prop('href')).toBe(
+      'https://www.google.com?1',
+    );
+    expect(tdElements.at(getTdIndex(2)).find('a').prop('href')).toBe(
+      'https://www.google.com?2',
+    );
   });
 });
diff --git a/superset-frontend/src/pages/DatasetList/index.tsx b/superset-frontend/src/pages/DatasetList/index.tsx
index d86d7a7b0f..8a39cb0463 100644
--- a/superset-frontend/src/pages/DatasetList/index.tsx
+++ b/superset-frontend/src/pages/DatasetList/index.tsx
@@ -70,6 +70,8 @@ import {
 } from 'src/features/datasets/constants';
 import DuplicateDatasetModal from 'src/features/datasets/DuplicateDatasetModal';
 import { useSelector } from 'react-redux';
+import { ModifiedInfo } from 'src/components/AuditInfo';
+import { QueryObjectColumns } from 'src/views/CRUD/types';
 
 const extensionsRegistry = getExtensionsRegistry();
 const DatasetDeleteRelatedExtension = extensionsRegistry.get(
@@ -380,26 +382,6 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({
         accessor: 'schema',
         size: 'lg',
       },
-      {
-        Cell: ({
-          row: {
-            original: { changed_on_delta_humanized: changedOn },
-          },
-        }: any) => <span className="no-wrap">{changedOn}</span>,
-        Header: t('Modified'),
-        accessor: 'changed_on_delta_humanized',
-        size: 'xl',
-      },
-      {
-        Cell: ({
-          row: {
-            original: { changed_by_name: changedByName },
-          },
-        }: any) => changedByName,
-        Header: t('Modified by'),
-        accessor: 'changed_by.first_name',
-        size: 'xl',
-      },
       {
         accessor: 'database',
         disableSortBy: true,
@@ -416,6 +398,19 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({
         disableSortBy: true,
         size: 'lg',
       },
+      {
+        Cell: ({
+          row: {
+            original: {
+              changed_on_delta_humanized: changedOn,
+              changed_by: changedBy,
+            },
+          },
+        }: any) => <ModifiedInfo date={changedOn} user={changedBy} />,
+        Header: t('Last modified'),
+        accessor: 'changed_on_delta_humanized',
+        size: 'xl',
+      },
       {
         accessor: 'sql',
         hidden: true,
@@ -515,6 +510,10 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({
         hidden: !canEdit && !canDelete && !canDuplicate,
         disableSortBy: true,
       },
+      {
+        accessor: QueryObjectColumns.changed_by,
+        hidden: true,
+      },
     ],
     [canEdit, canDelete, canExport, openDatasetEditModal, canDuplicate, user],
   );
@@ -522,31 +521,23 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({
   const filterTypes: Filters = useMemo(
     () => [
       {
-        Header: t('Search'),
+        Header: t('Name'),
         key: 'search',
         id: 'table_name',
         input: 'search',
         operator: FilterOperator.contains,
       },
       {
-        Header: t('Owner'),
-        key: 'owner',
-        id: 'owners',
+        Header: t('Type'),
+        key: 'sql',
+        id: 'sql',
         input: 'select',
-        operator: FilterOperator.relationManyMany,
+        operator: FilterOperator.datasetIsNullOrEmpty,
         unfilteredLabel: 'All',
-        fetchSelects: createFetchRelated(
-          'dataset',
-          'owners',
-          createErrorHandler(errMsg =>
-            t(
-              'An error occurred while fetching dataset owner values: %s',
-              errMsg,
-            ),
-          ),
-          user,
-        ),
-        paginate: true,
+        selects: [
+          { label: t('Virtual'), value: false },
+          { label: t('Physical'), value: true },
+        ],
       },
       {
         Header: t('Database'),
@@ -581,16 +572,24 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({
         paginate: true,
       },
       {
-        Header: t('Type'),
-        key: 'sql',
-        id: 'sql',
+        Header: t('Owner'),
+        key: 'owner',
+        id: 'owners',
         input: 'select',
-        operator: FilterOperator.datasetIsNullOrEmpty,
+        operator: FilterOperator.relationManyMany,
         unfilteredLabel: 'All',
-        selects: [
-          { label: t('Virtual'), value: false },
-          { label: t('Physical'), value: true },
-        ],
+        fetchSelects: createFetchRelated(
+          'dataset',
+          'owners',
+          createErrorHandler(errMsg =>
+            t(
+              'An error occurred while fetching dataset owner values: %s',
+              errMsg,
+            ),
+          ),
+          user,
+        ),
+        paginate: true,
       },
       {
         Header: t('Certified'),
@@ -605,6 +604,26 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({
           { label: t('No'), value: false },
         ],
       },
+      {
+        Header: t('Modified by'),
+        key: 'changed_by',
+        id: 'changed_by',
+        input: 'select',
+        operator: FilterOperator.relationOneMany,
+        unfilteredLabel: t('All'),
+        fetchSelects: createFetchRelated(
+          'dataset',
+          'changed_by',
+          createErrorHandler(errMsg =>
+            t(
+              'An error occurred while fetching dataset datasource values: %s',
+              errMsg,
+            ),
+          ),
+          user,
+        ),
+        paginate: true,
+      },
     ],
     [user],
   );
diff --git a/superset-frontend/src/pages/QueryHistoryList/index.tsx b/superset-frontend/src/pages/QueryHistoryList/index.tsx
index 77177188e0..94b646d9e4 100644
--- a/superset-frontend/src/pages/QueryHistoryList/index.tsx
+++ b/superset-frontend/src/pages/QueryHistoryList/index.tsx
@@ -53,6 +53,7 @@ import { QueryObject, QueryObjectColumns } from 'src/views/CRUD/types';
 import Icons from 'src/components/Icons';
 import QueryPreviewModal from 'src/features/queries/QueryPreviewModal';
 import { addSuccessToast } from 'src/components/MessageToasts/actions';
+import getOwnerName from 'src/utils/getOwnerName';
 
 const PAGE_SIZE = 25;
 const SQL_PREVIEW_MAX_LINES = 4;
@@ -311,7 +312,7 @@ function QueryList({ addDangerToast }: QueryListProps) {
           row: {
             original: { user },
           },
-        }: any) => (user ? `${user.first_name} ${user.last_name}` : ''),
+        }: any) => getOwnerName(user),
       },
       {
         accessor: QueryObjectColumns.user,
diff --git a/superset-frontend/src/pages/RowLevelSecurityList/RowLevelSecurityList.test.tsx b/superset-frontend/src/pages/RowLevelSecurityList/RowLevelSecurityList.test.tsx
index a4621ed10e..6721f73add 100644
--- a/superset-frontend/src/pages/RowLevelSecurityList/RowLevelSecurityList.test.tsx
+++ b/superset-frontend/src/pages/RowLevelSecurityList/RowLevelSecurityList.test.tsx
@@ -187,8 +187,8 @@ describe('RuleList RTL', () => {
     const searchFilters = screen.queryAllByTestId('filters-search');
     expect(searchFilters).toHaveLength(2);
 
-    const typeFilter = await screen.findByTestId('filters-select');
-    expect(typeFilter).toBeInTheDocument();
+    const typeFilter = screen.queryAllByTestId('filters-select');
+    expect(typeFilter).toHaveLength(2);
   });
 
   it('renders correct list columns', async () => {
@@ -201,7 +201,7 @@ describe('RuleList RTL', () => {
     const fitlerTypeColumn = await within(table).findByText('Filter Type');
     const groupKeyColumn = await within(table).findByText('Group Key');
     const clauseColumn = await within(table).findByText('Clause');
-    const modifiedColumn = await within(table).findByText('Modified');
+    const modifiedColumn = await within(table).findByText('Last modified');
     const actionsColumn = await within(table).findByText('Actions');
 
     expect(nameColumn).toBeInTheDocument();
diff --git a/superset-frontend/src/pages/RowLevelSecurityList/index.tsx b/superset-frontend/src/pages/RowLevelSecurityList/index.tsx
index 3c1e3b8aae..bef42284d0 100644
--- a/superset-frontend/src/pages/RowLevelSecurityList/index.tsx
+++ b/superset-frontend/src/pages/RowLevelSecurityList/index.tsx
@@ -33,7 +33,9 @@ import rison from 'rison';
 import { useListViewResource } from 'src/views/CRUD/hooks';
 import RowLevelSecurityModal from 'src/features/rls/RowLevelSecurityModal';
 import { RLSObject } from 'src/features/rls/types';
-import { createErrorHandler } from 'src/views/CRUD/utils';
+import { createErrorHandler, createFetchRelated } from 'src/views/CRUD/utils';
+import { ModifiedInfo } from 'src/components/AuditInfo';
+import { QueryObjectColumns } from 'src/views/CRUD/types';
 
 const Actions = styled.div`
   color: ${({ theme }) => theme.colors.grayscale.base};
@@ -43,7 +45,7 @@ interface RLSProps {
   addDangerToast: (msg: string) => void;
   addSuccessToast: (msg: string) => void;
   user: {
-    userId?: string | number;
+    userId: string | number;
     firstName: string;
     lastName: string;
   };
@@ -146,10 +148,13 @@ function RowLevelSecurityList(props: RLSProps) {
       {
         Cell: ({
           row: {
-            original: { changed_on_delta_humanized: changedOn },
+            original: {
+              changed_on_delta_humanized: changedOn,
+              changed_by: changedBy,
+            },
           },
-        }: any) => <span className="no-wrap">{changedOn}</span>,
-        Header: t('Modified'),
+        }: any) => <ModifiedInfo date={changedOn} user={changedBy} />,
+        Header: t('Last modified'),
         accessor: 'changed_on_delta_humanized',
         size: 'xl',
       },
@@ -218,6 +223,10 @@ function RowLevelSecurityList(props: RLSProps) {
         hidden: !canEdit && !canWrite && !canExport,
         disableSortBy: true,
       },
+      {
+        accessor: QueryObjectColumns.changed_by,
+        hidden: true,
+      },
     ],
     [
       user.userId,
@@ -270,6 +279,26 @@ function RowLevelSecurityList(props: RLSProps) {
         input: 'search',
         operator: FilterOperator.startsWith,
       },
+      {
+        Header: t('Modified by'),
+        key: 'changed_by',
+        id: 'changed_by',
+        input: 'select',
+        operator: FilterOperator.relationOneMany,
+        unfilteredLabel: t('All'),
+        fetchSelects: createFetchRelated(
+          'rowlevelsecurity',
+          'changed_by',
+          createErrorHandler(errMsg =>
+            t(
+              'An error occurred while fetching dataset datasource values: %s',
+              errMsg,
+            ),
+          ),
+          user,
+        ),
+        paginate: true,
+      },
     ],
     [user],
   );
diff --git a/superset-frontend/src/pages/SavedQueryList/index.tsx b/superset-frontend/src/pages/SavedQueryList/index.tsx
index 3ee62c2ce6..d48ffef8c9 100644
--- a/superset-frontend/src/pages/SavedQueryList/index.tsx
+++ b/superset-frontend/src/pages/SavedQueryList/index.tsx
@@ -18,20 +18,19 @@
  */
 
 import {
-  isFeatureEnabled,
   FeatureFlag,
+  isFeatureEnabled,
   styled,
   SupersetClient,
   t,
 } from '@superset-ui/core';
-import React, { useState, useMemo, useCallback } from 'react';
+import React, { useCallback, useMemo, useState } from 'react';
 import { Link, useHistory } from 'react-router-dom';
 import rison from 'rison';
-import moment from 'moment';
 import {
-  createFetchRelated,
-  createFetchDistinct,
   createErrorHandler,
+  createFetchDistinct,
+  createFetchRelated,
 } from 'src/views/CRUD/utils';
 import { useSelector } from 'react-redux';
 import Popover from 'src/components/Popover';
@@ -39,11 +38,11 @@ import withToasts from 'src/components/MessageToasts/withToasts';
 import { useListViewResource } from 'src/views/CRUD/hooks';
 import ConfirmStatusChange from 'src/components/ConfirmStatusChange';
 import handleResourceExport from 'src/utils/export';
-import SubMenu, { SubMenuProps, ButtonProps } from 'src/features/home/SubMenu';
+import SubMenu, { ButtonProps, SubMenuProps } from 'src/features/home/SubMenu';
 import ListView, {
-  ListViewProps,
-  Filters,
   FilterOperator,
+  Filters,
+  ListViewProps,
 } from 'src/components/ListView';
 import Loading from 'src/components/Loading';
 import DeleteModal from 'src/components/DeleteModal';
@@ -51,15 +50,14 @@ import ActionsBar, { ActionProps } from 'src/components/ListView/ActionsBar';
 import { TagsList } from 'src/components/Tags';
 import { Tooltip } from 'src/components/Tooltip';
 import { commonMenuData } from 'src/features/home/commonMenuData';
-import { SavedQueryObject } from 'src/views/CRUD/types';
+import { QueryObjectColumns, SavedQueryObject } from 'src/views/CRUD/types';
 import copyTextToClipboard from 'src/utils/copy';
 import Tag from 'src/types/TagType';
 import ImportModelsModal from 'src/components/ImportModal/index';
+import { ModifiedInfo } from 'src/components/AuditInfo';
+import { loadTags } from 'src/components/Tags/utils';
 import Icons from 'src/components/Icons';
-import {
-  BootstrapUser,
-  UserWithPermissionsAndRoles,
-} from 'src/types/bootstrapTypes';
+import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes';
 import SavedQueryPreviewModal from 'src/features/queries/SavedQueryPreviewModal';
 import { findPermission } from 'src/utils/findPermission';
 
@@ -80,7 +78,11 @@ const CONFIRM_OVERWRITE_MESSAGE = t(
 interface SavedQueryListProps {
   addDangerToast: (msg: string) => void;
   addSuccessToast: (msg: string) => void;
-  user: BootstrapUser;
+  user: {
+    userId: string | number;
+    firstName: string;
+    lastName: string;
+  };
 }
 
 const StyledTableLabel = styled.div`
@@ -99,6 +101,7 @@ const StyledPopoverItem = styled.div`
 function SavedQueryList({
   addDangerToast,
   addSuccessToast,
+  user,
 }: SavedQueryListProps) {
   const {
     state: {
@@ -348,41 +351,6 @@ function SavedQueryList({
         size: 'xl',
         disableSortBy: true,
       },
-      {
-        Cell: ({
-          row: {
-            original: { created_on: createdOn },
-          },
-        }: any) => {
-          const date = new Date(createdOn);
-          const utc = new Date(
-            Date.UTC(
-              date.getFullYear(),
-              date.getMonth(),
-              date.getDate(),
-              date.getHours(),
-              date.getMinutes(),
-              date.getSeconds(),
-              date.getMilliseconds(),
-            ),
-          );
-
-          return moment(utc).fromNow();
-        },
-        Header: t('Created on'),
-        accessor: 'created_on',
-        size: 'xl',
-      },
-      {
-        Cell: ({
-          row: {
-            original: { changed_on_delta_humanized: changedOn },
-          },
-        }: any) => changedOn,
-        Header: t('Modified'),
-        accessor: 'changed_on_delta_humanized',
-        size: 'xl',
-      },
       {
         Cell: ({
           row: {
@@ -397,6 +365,19 @@ function SavedQueryList({
         disableSortBy: true,
         hidden: !isFeatureEnabled(FeatureFlag.TAGGING_SYSTEM),
       },
+      {
+        Cell: ({
+          row: {
+            original: {
+              changed_by: changedBy,
+              changed_on_delta_humanized: changedOn,
+            },
+          },
+        }: any) => <ModifiedInfo user={changedBy} date={changedOn} />,
+        Header: t('Last modified'),
+        accessor: 'changed_on_delta_humanized',
+        size: 'xl',
+      },
       {
         Cell: ({ row: { original } }: any) => {
           const handlePreview = () => {
@@ -452,12 +433,23 @@ function SavedQueryList({
         id: 'actions',
         disableSortBy: true,
       },
+      {
+        accessor: QueryObjectColumns.changed_by,
+        hidden: true,
+      },
     ],
     [canDelete, canEdit, canExport, copyQueryLink, handleSavedQueryPreview],
   );
 
   const filters: Filters = useMemo(
     () => [
+      {
+        Header: t('Name'),
+        id: 'label',
+        key: 'search',
+        input: 'search',
+        operator: FilterOperator.allText,
+      },
       {
         Header: t('Database'),
         key: 'database',
@@ -497,28 +489,42 @@ function SavedQueryList({
         ),
         paginate: true,
       },
-
+      ...((isFeatureEnabled(FeatureFlag.TAGGING_SYSTEM) && canReadTag
+        ? [
+            {
+              Header: t('Tag'),
+              id: 'tags',
+              key: 'tags',
+              input: 'select',
+              operator: FilterOperator.savedQueryTags,
+              fetchSelects: loadTags,
+            },
+          ]
+        : []) as Filters),
       {
-        Header: t('Search'),
-        id: 'label',
-        key: 'search',
-        input: 'search',
-        operator: FilterOperator.allText,
+        Header: t('Modified by'),
+        key: 'changed_by',
+        id: 'changed_by',
+        input: 'select',
+        operator: FilterOperator.relationOneMany,
+        unfilteredLabel: t('All'),
+        fetchSelects: createFetchRelated(
+          'saved_query',
+          'changed_by',
+          createErrorHandler(errMsg =>
+            t(
+              'An error occurred while fetching dataset datasource values: %s',
+              errMsg,
+            ),
+          ),
+          user,
+        ),
+        paginate: true,
       },
     ],
     [addDangerToast],
   );
 
-  if (isFeatureEnabled(FeatureFlag.TAGGING_SYSTEM) && canReadTag) {
-    filters.push({
-      Header: t('Tags'),
-      id: 'tags',
-      key: 'tags',
-      input: 'search',
-      operator: FilterOperator.savedQueryTags,
-    });
-  }
-
   return (
     <>
       <SubMenu {...menuData} />
diff --git a/superset-frontend/src/pages/Tags/index.tsx b/superset-frontend/src/pages/Tags/index.tsx
index a66d7c7b61..d395ce7cde 100644
--- a/superset-frontend/src/pages/Tags/index.tsx
+++ b/superset-frontend/src/pages/Tags/index.tsx
@@ -19,9 +19,9 @@
 import React, { useMemo, useState } from 'react';
 import { isFeatureEnabled, FeatureFlag, t } from '@superset-ui/core';
 import {
-  createFetchRelated,
-  createErrorHandler,
   Actions,
+  createErrorHandler,
+  createFetchRelated,
 } from 'src/views/CRUD/utils';
 import { useListViewResource, useFavoriteStatus } from 'src/views/CRUD/hooks';
 import ConfirmStatusChange from 'src/components/ConfirmStatusChange';
@@ -35,13 +35,13 @@ import { dangerouslyGetItemDoNotUse } from 'src/utils/localStorageHelpers';
 import withToasts from 'src/components/MessageToasts/withToasts';
 import Icons from 'src/components/Icons';
 import { Tooltip } from 'src/components/Tooltip';
-import FacePile from 'src/components/FacePile';
 import { Link } from 'react-router-dom';
 import { deleteTags } from 'src/features/tags/tags';
 import { Tag as AntdTag } from 'antd';
-import { Tag } from 'src/views/CRUD/types';
+import { QueryObjectColumns, Tag } from 'src/views/CRUD/types';
 import TagModal from 'src/features/tags/TagModal';
 import FaveStar from 'src/components/FaveStar';
+import { ModifiedInfo } from 'src/components/AuditInfo';
 
 const PAGE_SIZE = 25;
 
@@ -56,11 +56,8 @@ interface TagListProps {
 }
 
 function TagList(props: TagListProps) {
-  const {
-    addDangerToast,
-    addSuccessToast,
-    user: { userId },
-  } = props;
+  const { addDangerToast, addSuccessToast, user } = props;
+  const { userId } = user;
 
   const {
     state: {
@@ -162,24 +159,16 @@ function TagList(props: TagListProps) {
       {
         Cell: ({
           row: {
-            original: { changed_on_delta_humanized: changedOn },
+            original: {
+              changed_on_delta_humanized: changedOn,
+              changed_by: changedBy,
+            },
           },
-        }: any) => <span className="no-wrap">{changedOn}</span>,
-        Header: t('Modified'),
+        }: any) => <ModifiedInfo date={changedOn} user={changedBy} />,
+        Header: t('Last modified'),
         accessor: 'changed_on_delta_humanized',
         size: 'xl',
       },
-      {
-        Cell: ({
-          row: {
-            original: { created_by: createdBy },
-          },
-        }: any) => (createdBy ? <FacePile users={[createdBy]} /> : ''),
-        Header: t('Created by'),
-        accessor: 'created_by',
-        disableSortBy: true,
-        size: 'xl',
-      },
       {
         Cell: ({ row: { original } }: any) => {
           const handleEdit = () => handleTagEdit(original);
@@ -238,6 +227,10 @@ function TagList(props: TagListProps) {
         hidden: !canDelete,
         disableSortBy: true,
       },
+      {
+        accessor: QueryObjectColumns.changed_by,
+        hidden: true,
+      },
     ],
     [userId, canDelete, refreshData, addSuccessToast, addDangerToast],
   );
@@ -245,32 +238,31 @@ function TagList(props: TagListProps) {
   const filters: Filters = useMemo(() => {
     const filters_list = [
       {
-        Header: t('Created by'),
-        id: 'created_by',
+        Header: t('Name'),
+        id: 'name',
+        input: 'search',
+        operator: FilterOperator.contains,
+      },
+      {
+        Header: t('Modified by'),
+        key: 'changed_by',
+        id: 'changed_by',
         input: 'select',
         operator: FilterOperator.relationOneMany,
         unfilteredLabel: t('All'),
         fetchSelects: createFetchRelated(
           'tag',
-          'created_by',
+          'changed_by',
           createErrorHandler(errMsg =>
-            addDangerToast(
-              t(
-                'An error occurred while fetching tag created by values: %s',
-                errMsg,
-              ),
+            t(
+              'An error occurred while fetching dataset datasource values: %s',
+              errMsg,
             ),
           ),
-          props.user,
+          user,
         ),
         paginate: true,
       },
-      {
-        Header: t('Search'),
-        id: 'name',
-        input: 'search',
-        operator: FilterOperator.contains,
-      },
     ] as Filters;
     return filters_list;
   }, [addDangerToast, props.user]);
diff --git a/superset-frontend/src/features/cssTemplates/types.ts b/superset-frontend/src/utils/getOwnerName.test.ts
similarity index 73%
copy from superset-frontend/src/features/cssTemplates/types.ts
copy to superset-frontend/src/utils/getOwnerName.test.ts
index 1bb5b2e659..a4a25e57b2 100644
--- a/superset-frontend/src/features/cssTemplates/types.ts
+++ b/superset-frontend/src/utils/getOwnerName.test.ts
@@ -16,17 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-type CreatedByUser = {
-  id: number;
-  first_name: string;
-  last_name: string;
-};
+import getOwnerName from './getOwnerName';
 
-export type TemplateObject = {
-  id?: number;
-  changed_on_delta_humanized?: string;
-  created_on?: string;
-  created_by?: CreatedByUser;
-  css?: string;
-  template_name: string;
-};
+test('render owner name correctly', () => {
+  expect(getOwnerName({ id: 1, first_name: 'Foo', last_name: 'Bar' })).toEqual(
+    'Foo Bar',
+  );
+});
+
+test('return empty string for undefined owner', () => {
+  expect(getOwnerName(undefined)).toEqual('');
+});
diff --git a/superset-frontend/src/features/cssTemplates/types.ts b/superset-frontend/src/utils/getOwnerName.ts
similarity index 75%
copy from superset-frontend/src/features/cssTemplates/types.ts
copy to superset-frontend/src/utils/getOwnerName.ts
index 1bb5b2e659..2534c45f2c 100644
--- a/superset-frontend/src/features/cssTemplates/types.ts
+++ b/superset-frontend/src/utils/getOwnerName.ts
@@ -16,17 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-type CreatedByUser = {
-  id: number;
-  first_name: string;
-  last_name: string;
-};
+import Owner from 'src/types/Owner';
 
-export type TemplateObject = {
-  id?: number;
-  changed_on_delta_humanized?: string;
-  created_on?: string;
-  created_by?: CreatedByUser;
-  css?: string;
-  template_name: string;
-};
+export default function getOwnerName(owner?: Owner): string {
+  if (!owner) {
+    return '';
+  }
+  return `${owner.first_name} ${owner.last_name}`;
+}
diff --git a/superset-frontend/src/views/CRUD/types.ts b/superset-frontend/src/views/CRUD/types.ts
index 5a53b57696..2fff111b47 100644
--- a/superset-frontend/src/views/CRUD/types.ts
+++ b/superset-frontend/src/views/CRUD/types.ts
@@ -112,6 +112,7 @@ export interface QueryObject {
 export enum QueryObjectColumns {
   id = 'id',
   changed_on = 'changed_on',
+  changed_by = 'changed_by',
   database = 'database',
   database_name = 'database.database_name',
   schema = 'schema',
@@ -138,17 +139,11 @@ export type ImportResourceName =
 
 export interface Tag {
   changed_on_delta_humanized: string;
-  changed_by: {
-    first_name: string;
-    last_name: string;
-  };
+  changed_by: Owner;
   created_on_delta_humanized: string;
   name: string;
   id: number;
-  created_by: {
-    first_name: string;
-    last_name: string;
-  };
+  created_by: Owner;
   description: string;
   type: string;
 }
diff --git a/superset/annotation_layers/api.py b/superset/annotation_layers/api.py
index 886c151a68..5606e944ef 100644
--- a/superset/annotation_layers/api.py
+++ b/superset/annotation_layers/api.py
@@ -99,7 +99,7 @@ class AnnotationLayerRestApi(BaseSupersetModelRestApi):
     ]
 
     search_filters = {"name": [AnnotationLayerAllTextFilter]}
-    allowed_rel_fields = {"created_by"}
+    allowed_rel_fields = {"created_by", "changed_by"}
 
     apispec_parameter_schemas = {
         "get_delete_ids_schema": get_delete_ids_schema,
diff --git a/superset/charts/api.py b/superset/charts/api.py
index ea705f0aa9..191f09c66e 100644
--- a/superset/charts/api.py
+++ b/superset/charts/api.py
@@ -273,7 +273,7 @@ class ChartRestApi(BaseSupersetModelRestApi):
         "created_by": RelatedFieldFilter("first_name", FilterRelatedOwners),
     }
 
-    allowed_rel_fields = {"owners", "created_by"}
+    allowed_rel_fields = {"owners", "created_by", "changed_by"}
 
     @expose("/", methods=("POST",))
     @protect()
diff --git a/superset/css_templates/api.py b/superset/css_templates/api.py
index 25f4d50f30..ac222da66f 100644
--- a/superset/css_templates/api.py
+++ b/superset/css_templates/api.py
@@ -54,6 +54,10 @@ class CssTemplateRestApi(BaseSupersetModelRestApi):
     allow_browser_login = True
 
     show_columns = [
+        "changed_on_delta_humanized",
+        "changed_by.first_name",
+        "changed_by.id",
+        "changed_by.last_name",
         "created_by.first_name",
         "created_by.id",
         "created_by.last_name",
@@ -79,7 +83,7 @@ class CssTemplateRestApi(BaseSupersetModelRestApi):
     order_columns = ["template_name"]
 
     search_filters = {"template_name": [CssTemplateAllTextFilter]}
-    allowed_rel_fields = {"created_by"}
+    allowed_rel_fields = {"created_by", "changed_by"}
 
     apispec_parameter_schemas = {
         "get_delete_ids_schema": get_delete_ids_schema,
diff --git a/superset/dashboards/api.py b/superset/dashboards/api.py
index be773b83c3..cf75a644fb 100644
--- a/superset/dashboards/api.py
+++ b/superset/dashboards/api.py
@@ -261,7 +261,7 @@ class DashboardRestApi(BaseSupersetModelRestApi):
         "roles": RelatedFieldFilter("name", FilterRelatedRoles),
         "created_by": RelatedFieldFilter("first_name", FilterRelatedOwners),
     }
-    allowed_rel_fields = {"owners", "roles", "created_by"}
+    allowed_rel_fields = {"owners", "roles", "created_by", "changed_by"}
 
     openapi_spec_tag = "Dashboards"
     """ Override the name set for this collection of endpoints """
diff --git a/superset/databases/api.py b/superset/databases/api.py
index df69d9ccd7..8de84a16af 100644
--- a/superset/databases/api.py
+++ b/superset/databases/api.py
@@ -111,6 +111,7 @@ class DatabaseRestApi(BaseSupersetModelRestApi):
     include_route_methods = RouteMethod.REST_MODEL_VIEW_CRUD_SET | {
         RouteMethod.EXPORT,
         RouteMethod.IMPORT,
+        RouteMethod.RELATED,
         "tables",
         "table_metadata",
         "table_extra_metadata",
@@ -162,6 +163,8 @@ class DatabaseRestApi(BaseSupersetModelRestApi):
         "backend",
         "changed_on",
         "changed_on_delta_humanized",
+        "changed_by.first_name",
+        "changed_by.last_name",
         "created_by.first_name",
         "created_by.last_name",
         "database_name",
@@ -194,7 +197,17 @@ class DatabaseRestApi(BaseSupersetModelRestApi):
 
     edit_columns = add_columns
 
+    search_columns = [
+        "allow_file_upload",
+        "allow_dml",
+        "allow_run_async",
+        "created_by",
+        "changed_by",
+        "database_name",
+        "expose_in_sqllab",
+    ]
     search_filters = {"allow_file_upload": [DatabaseUploadEnabledFilter]}
+    allowed_rel_fields = {"changed_by", "created_by"}
 
     list_select_columns = list_columns + ["extra", "sqlalchemy_uri", "password"]
     order_columns = [
diff --git a/superset/datasets/api.py b/superset/datasets/api.py
index e256ff99d6..bc4a42e58e 100644
--- a/superset/datasets/api.py
+++ b/superset/datasets/api.py
@@ -247,8 +247,17 @@ class DatasetRestApi(BaseSupersetModelRestApi):
         "sql": [DatasetIsNullOrEmptyFilter],
         "id": [DatasetCertifiedFilter],
     }
-    search_columns = ["id", "database", "owners", "schema", "sql", "table_name"]
-    allowed_rel_fields = {"database", "owners"}
+    search_columns = [
+        "id",
+        "database",
+        "owners",
+        "schema",
+        "sql",
+        "table_name",
+        "created_by",
+        "changed_by",
+    ]
+    allowed_rel_fields = {"database", "owners", "created_by", "changed_by"}
     allowed_distinct_fields = {"schema"}
 
     apispec_parameter_schemas = {
diff --git a/superset/queries/saved_queries/api.py b/superset/queries/saved_queries/api.py
index 25ac520e45..ce283dd6d6 100644
--- a/superset/queries/saved_queries/api.py
+++ b/superset/queries/saved_queries/api.py
@@ -82,7 +82,11 @@ class SavedQueryRestApi(BaseSupersetModelRestApi):
     base_filters = [["id", SavedQueryFilter, lambda: []]]
 
     show_columns = [
+        "changed_on",
         "changed_on_delta_humanized",
+        "changed_by.first_name",
+        "changed_by.id",
+        "changed_by.last_name",
         "created_by.first_name",
         "created_by.id",
         "created_by.last_name",
@@ -97,7 +101,11 @@ class SavedQueryRestApi(BaseSupersetModelRestApi):
         "template_parameters",
     ]
     list_columns = [
+        "changed_on",
         "changed_on_delta_humanized",
+        "changed_by.first_name",
+        "changed_by.id",
+        "changed_by.last_name",
         "created_on",
         "created_by.first_name",
         "created_by.id",
@@ -140,7 +148,7 @@ class SavedQueryRestApi(BaseSupersetModelRestApi):
         "last_run_delta_humanized",
     ]
 
-    search_columns = ["id", "database", "label", "schema", "created_by"]
+    search_columns = ["id", "database", "label", "schema", "created_by", "changed_by"]
     if is_feature_enabled("TAGGING_SYSTEM"):
         search_columns += ["tags"]
     search_filters = {
@@ -161,7 +169,7 @@ class SavedQueryRestApi(BaseSupersetModelRestApi):
         "database": "database_name",
     }
     base_related_field_filters = {"database": [["id", DatabaseFilter, lambda: []]]}
-    allowed_rel_fields = {"database"}
+    allowed_rel_fields = {"database", "changed_by", "created_by"}
     allowed_distinct_fields = {"schema"}
 
     def pre_add(self, item: SavedQuery) -> None:
diff --git a/superset/reports/api.py b/superset/reports/api.py
index ab4f80ae15..8238213fef 100644
--- a/superset/reports/api.py
+++ b/superset/reports/api.py
@@ -198,6 +198,7 @@ class ReportScheduleRestApi(BaseSupersetModelRestApi):
     search_columns = [
         "name",
         "active",
+        "changed_by",
         "created_by",
         "owners",
         "type",
@@ -207,7 +208,14 @@ class ReportScheduleRestApi(BaseSupersetModelRestApi):
         "chart_id",
     ]
     search_filters = {"name": [ReportScheduleAllTextFilter]}
-    allowed_rel_fields = {"owners", "chart", "dashboard", "database", "created_by"}
+    allowed_rel_fields = {
+        "owners",
+        "chart",
+        "dashboard",
+        "database",
+        "created_by",
+        "changed_by",
+    }
 
     base_related_field_filters = {
         "chart": [["id", ChartFilter, lambda: []]],
diff --git a/superset/row_level_security/api.py b/superset/row_level_security/api.py
index e7347f5280..fc505e724f 100644
--- a/superset/row_level_security/api.py
+++ b/superset/row_level_security/api.py
@@ -77,6 +77,9 @@ class RLSRestApi(BaseSupersetModelRestApi):
         "roles.name",
         "clause",
         "changed_on_delta_humanized",
+        "changed_by.first_name",
+        "changed_by.last_name",
+        "changed_by.id",
         "group_key",
     ]
     order_columns = [
@@ -115,6 +118,8 @@ class RLSRestApi(BaseSupersetModelRestApi):
         "roles",
         "group_key",
         "clause",
+        "created_by",
+        "changed_by",
     )
     edit_columns = add_columns
 
@@ -123,7 +128,7 @@ class RLSRestApi(BaseSupersetModelRestApi):
     add_model_schema = RLSPostSchema()
     edit_model_schema = RLSPutSchema()
 
-    allowed_rel_fields = {"tables", "roles"}
+    allowed_rel_fields = {"tables", "roles", "created_by", "changed_by"}
     base_related_field_filters = {
         "tables": [["id", DatasourceFilter, lambda: []]],
         "roles": [["id", BaseFilterRelatedRoles, lambda: []]],
diff --git a/superset/row_level_security/schemas.py b/superset/row_level_security/schemas.py
index 6c8249b875..f02767ec13 100644
--- a/superset/row_level_security/schemas.py
+++ b/superset/row_level_security/schemas.py
@@ -20,6 +20,7 @@ from marshmallow import fields, Schema
 from marshmallow.validate import Length, OneOf
 
 from superset.connectors.sqla.models import RowLevelSecurityFilter
+from superset.dashboards.schemas import UserSchema
 from superset.utils.core import RowLevelSecurityFilterType
 
 id_description = "Unique if of rls filter"
@@ -81,6 +82,7 @@ class RLSListSchema(Schema):
     )
     group_key = fields.String(metadata={"description": "group_key_description"})
     description = fields.String(metadata={"description": "description_description"})
+    changed_by = fields.Nested(UserSchema(exclude=["username"]))
 
 
 class RLSShowSchema(Schema):
diff --git a/superset/tags/api.py b/superset/tags/api.py
index a3c95a5814..c0df921e3e 100644
--- a/superset/tags/api.py
+++ b/superset/tags/api.py
@@ -117,7 +117,7 @@ class TagRestApi(BaseSupersetModelRestApi):
     related_field_filters = {
         "created_by": RelatedFieldFilter("first_name", FilterRelatedOwners),
     }
-    allowed_rel_fields = {"created_by"}
+    allowed_rel_fields = {"created_by", "changed_by"}
 
     add_model_schema = TagPostSchema()
     edit_model_schema = TagPutSchema()
diff --git a/tests/integration_tests/css_templates/api_tests.py b/tests/integration_tests/css_templates/api_tests.py
index b28cca955c..ceb46f553b 100644
--- a/tests/integration_tests/css_templates/api_tests.py
+++ b/tests/integration_tests/css_templates/api_tests.py
@@ -19,6 +19,8 @@
 import json
 import pytest
 import prison
+from datetime import datetime
+from freezegun import freeze_time
 from sqlalchemy.sql import func
 
 import tests.integration_tests.test_app
@@ -189,20 +191,27 @@ class TestCssTemplateApi(SupersetTestCase):
         """
         CSS Template API: Test get CSS Template
         """
-        css_template = (
-            db.session.query(CssTemplate)
-            .filter(CssTemplate.template_name == "template_name1")
-            .one_or_none()
-        )
-        self.login(username="admin")
-        uri = f"api/v1/css_template/{css_template.id}"
-        rv = self.get_assert_metric(uri, "get")
+        with freeze_time(datetime.now()):
+            css_template = (
+                db.session.query(CssTemplate)
+                .filter(CssTemplate.template_name == "template_name1")
+                .one_or_none()
+            )
+            self.login(username="admin")
+            uri = f"api/v1/css_template/{css_template.id}"
+            rv = self.get_assert_metric(uri, "get")
         assert rv.status_code == 200
 
         expected_result = {
             "id": css_template.id,
             "template_name": "template_name1",
             "css": "css1",
+            "changed_by": {
+                "first_name": css_template.created_by.first_name,
+                "id": css_template.created_by.id,
+                "last_name": css_template.created_by.last_name,
+            },
+            "changed_on_delta_humanized": "now",
             "created_by": {
                 "first_name": css_template.created_by.first_name,
                 "id": css_template.created_by.id,
diff --git a/tests/integration_tests/databases/api_tests.py b/tests/integration_tests/databases/api_tests.py
index 496012390e..0bc1f245a1 100644
--- a/tests/integration_tests/databases/api_tests.py
+++ b/tests/integration_tests/databases/api_tests.py
@@ -197,6 +197,7 @@ class TestDatabaseApi(SupersetTestCase):
             "allows_subquery",
             "allows_virtual_table_explore",
             "backend",
+            "changed_by",
             "changed_on",
             "changed_on_delta_humanized",
             "created_by",
diff --git a/tests/integration_tests/queries/saved_queries/api_tests.py b/tests/integration_tests/queries/saved_queries/api_tests.py
index 09929e4d23..c51c0dcbf0 100644
--- a/tests/integration_tests/queries/saved_queries/api_tests.py
+++ b/tests/integration_tests/queries/saved_queries/api_tests.py
@@ -17,6 +17,7 @@
 # isort:skip_file
 """Unit tests for Superset"""
 import json
+from datetime import datetime
 from io import BytesIO
 from typing import Optional
 from zipfile import is_zipfile, ZipFile
@@ -24,6 +25,7 @@ from zipfile import is_zipfile, ZipFile
 import yaml
 import pytest
 import prison
+from freezegun import freeze_time
 from sqlalchemy.sql import func, and_
 
 import tests.integration_tests.test_app
@@ -507,14 +509,17 @@ class TestSavedQueryApi(SupersetTestCase):
             db.session.query(SavedQuery).filter(SavedQuery.label == "label1").all()[0]
         )
         self.login(username="admin")
-        uri = f"api/v1/saved_query/{saved_query.id}"
-        rv = self.get_assert_metric(uri, "get")
-        assert rv.status_code == 200
+        with freeze_time(datetime.now()):
+            uri = f"api/v1/saved_query/{saved_query.id}"
+            rv = self.get_assert_metric(uri, "get")
+            assert rv.status_code == 200
 
         expected_result = {
             "id": saved_query.id,
             "database": {"id": saved_query.database.id, "database_name": "examples"},
             "description": "cool description",
+            "changed_by": None,
+            "changed_on_delta_humanized": "now",
             "created_by": {
                 "first_name": saved_query.created_by.first_name,
                 "id": saved_query.created_by.id,
@@ -527,9 +532,8 @@ class TestSavedQueryApi(SupersetTestCase):
             "template_parameters": None,
         }
         data = json.loads(rv.data.decode("utf-8"))
-        self.assertIn("changed_on_delta_humanized", data["result"])
         for key, value in data["result"].items():
-            if key not in ("changed_on_delta_humanized",):
+            if key != "changed_on":
                 assert value == expected_result[key]
 
     def test_get_saved_query_not_found(self):