diff --git a/react/src/App.tsx b/react/src/App.tsx
index 98b76919d6..ac61be4f63 100644
--- a/react/src/App.tsx
+++ b/react/src/App.tsx
@@ -60,8 +60,8 @@ const UserCredentialsPage = React.lazy(
   () => import('./pages/UserCredentialsPage'),
 );
 
-const ComputeSessionList = React.lazy(
-  () => import('./components/ComputeSessionList'),
+const ComputeSessionListPage = React.lazy(
+  () => import('./pages/ComputeSessionListPage'),
 );
 const AgentSummaryPage = React.lazy(() => import('./pages/AgentSummaryPage'));
 
@@ -142,7 +142,7 @@ const router = createBrowserRouter([
         handle: { labelKey: 'webui.menu.Sessions' },
         element: (
           <BAIErrorBoundary>
-            <ComputeSessionList />
+            <ComputeSessionListPage />
           </BAIErrorBoundary>
         ),
       },
diff --git a/react/src/components/BAILink.tsx b/react/src/components/BAILink.tsx
index 6bfd558e82..21b663ba04 100644
--- a/react/src/components/BAILink.tsx
+++ b/react/src/components/BAILink.tsx
@@ -15,7 +15,7 @@ const useStyles = createStyles(({ css, token }) => ({
 }));
 
 interface BAILinkProps extends LinkProps {
-  type: 'hover';
+  type?: 'hover';
 }
 const BAILink: React.FC<BAILinkProps> = ({ type, ...linkProps }) => {
   const { styles } = useStyles();
diff --git a/react/src/components/BAIPropertyFilter.tsx b/react/src/components/BAIPropertyFilter.tsx
index 0b1e16a5aa..114c685119 100644
--- a/react/src/components/BAIPropertyFilter.tsx
+++ b/react/src/components/BAIPropertyFilter.tsx
@@ -91,7 +91,7 @@ function trimFilterValue(filterValue: string): string {
 }
 
 export function mergeFilterValues(
-  filterStrings: Array<string | undefined>,
+  filterStrings: Array<string | undefined | null>,
   operator: string = '&',
 ) {
   const mergedFilter = _.join(
diff --git a/react/src/components/BAITable.tsx b/react/src/components/BAITable.tsx
index 51fbd8e1ca..9ae27f71ff 100644
--- a/react/src/components/BAITable.tsx
+++ b/react/src/components/BAITable.tsx
@@ -1,8 +1,9 @@
 import { useDebounce } from 'ahooks';
-import { GetProps, Table } from 'antd';
+import { ConfigProvider, GetProps, Table } from 'antd';
 import { createStyles } from 'antd-style';
 import { ColumnsType, ColumnType } from 'antd/es/table';
 import { TableProps } from 'antd/lib';
+import { ComponentToken } from 'antd/lib/table/style';
 import _ from 'lodash';
 import { useEffect, useMemo, useRef, useState } from 'react';
 import { Resizable, ResizeCallbackData } from 'react-resizable';
@@ -23,6 +24,11 @@ const useStyles = createStyles(({ token, css }) => ({
       whitespace: 'pre';
       wordwrap: 'break-word';
     }
+
+    thead.ant-table-thead > tr > th.ant-table-cell {
+      font-weight: 500;
+      color: ${token.colorTextTertiary};
+    }
   `,
 }));
 
@@ -94,6 +100,7 @@ const ResizableTitle = (
 interface BAITableProps<RecordType extends object = any>
   extends TableProps<RecordType> {
   resizable?: boolean;
+  tableComponentToken?: ComponentToken;
 }
 
 const columnKeyOrIndexKey = (column: any, index: number) =>
@@ -110,6 +117,7 @@ const BAITable = <RecordType extends object = any>({
   resizable = false,
   columns,
   components,
+  tableComponentToken,
   ...tableProps
 }: BAITableProps<RecordType>) => {
   const { styles } = useStyles();
@@ -145,22 +153,35 @@ const BAITable = <RecordType extends object = any>({
   }, [resizable, columns, resizedColumnWidths]);
 
   return (
-    <Table
-      sortDirections={['descend', 'ascend', 'descend']}
-      showSorterTooltip={false}
-      className={resizable ? styles.resizableTable : ''}
-      components={
-        resizable
-          ? _.merge(components || {}, {
-              header: {
-                cell: ResizableTitle,
+    <ConfigProvider
+      theme={
+        tableComponentToken
+          ? {
+              components: {
+                Table: tableComponentToken,
               },
-            })
-          : components
+            }
+          : undefined
       }
-      columns={mergedColumns}
-      {...tableProps}
-    />
+    >
+      <Table
+        size="small"
+        sortDirections={['descend', 'ascend', 'descend']}
+        showSorterTooltip={false}
+        className={resizable ? styles.resizableTable : ''}
+        components={
+          resizable
+            ? _.merge(components || {}, {
+                header: {
+                  cell: ResizableTitle,
+                },
+              })
+            : components
+        }
+        columns={mergedColumns}
+        {...tableProps}
+      />
+    </ConfigProvider>
   );
 };
 
diff --git a/react/src/components/ComputeSessionList.tsx b/react/src/components/ComputeSessionList.tsx
deleted file mode 100644
index a1a90a1ecc..0000000000
--- a/react/src/components/ComputeSessionList.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import SessionDetailAndContainerLogOpenerLegacy from './SessionDetailAndContainerLogOpenerLegacy';
-
-const ComputeSessionList = () => {
-  return (
-    <>
-      <SessionDetailAndContainerLogOpenerLegacy />
-    </>
-  );
-};
-
-export default ComputeSessionList;
diff --git a/react/src/components/ComputeSessionNodeItems/SessionOccupiedSlot.tsx b/react/src/components/ComputeSessionNodeItems/SessionOccupiedSlot.tsx
new file mode 100644
index 0000000000..c10d39883e
--- /dev/null
+++ b/react/src/components/ComputeSessionNodeItems/SessionOccupiedSlot.tsx
@@ -0,0 +1,54 @@
+import { convertBinarySizeUnit } from '../../helper';
+import { useResourceSlotsDetails } from '../../hooks/backendai';
+import { SessionOccupiedSlotFragment$key } from './__generated__/SessionOccupiedSlotFragment.graphql';
+import { Divider, Typography } from 'antd';
+import graphql from 'babel-plugin-relay/macro';
+import _ from 'lodash';
+import React from 'react';
+import { useFragment } from 'react-relay';
+
+interface OccupiedSlotViewProps {
+  sessionFrgmt: SessionOccupiedSlotFragment$key;
+  type: 'cpu' | 'mem' | 'accelerator';
+}
+const SessionOccupiedSlot: React.FC<OccupiedSlotViewProps> = ({
+  type,
+  sessionFrgmt,
+}) => {
+  const { deviceMetadata } = useResourceSlotsDetails();
+  const session = useFragment(
+    graphql`
+      fragment SessionOccupiedSlotFragment on ComputeSessionNode {
+        id
+        occupied_slots
+      }
+    `,
+    sessionFrgmt,
+  );
+
+  const occupiedSlots = JSON.parse(session.occupied_slots || '{}');
+
+  if (type === 'cpu') {
+    return occupiedSlots.cpu ?? '-';
+  } else if (type === 'mem') {
+    const mem = occupiedSlots.mem ?? '-';
+    return mem === '-' ? mem : convertBinarySizeUnit(mem, 'G')?.number + ' GiB';
+  } else if (type === 'accelerator') {
+    const occupiedAccelerators = _.omit(occupiedSlots, ['cpu', 'mem']);
+    return _.isEmpty(occupiedAccelerators)
+      ? '-'
+      : _.map(occupiedAccelerators, (value, key) => {
+          return (
+            <>
+              <Typography.Text>{value}</Typography.Text>
+              <Divider type="vertical" />
+              <Typography.Text>
+                {deviceMetadata?.[key]?.human_readable_name}
+              </Typography.Text>
+            </>
+          );
+        });
+  }
+};
+
+export default SessionOccupiedSlot;
diff --git a/react/src/components/ComputeSessionNodeItems/SessionReservation.tsx b/react/src/components/ComputeSessionNodeItems/SessionReservation.tsx
index 9f0d9aed9f..a3bc0e9a37 100644
--- a/react/src/components/ComputeSessionNodeItems/SessionReservation.tsx
+++ b/react/src/components/ComputeSessionNodeItems/SessionReservation.tsx
@@ -1,3 +1,4 @@
+import { formatDurationAsDays } from '../../helper';
 import { useSuspendedBackendaiClient } from '../../hooks';
 import BAIIntervalView from '../BAIIntervalView';
 import DoubleTag from '../DoubleTag';
@@ -10,8 +11,8 @@ import { useFragment } from 'react-relay';
 
 const SessionReservation: React.FC<{
   sessionFrgmt: SessionReservationFragment$key;
-}> = ({ sessionFrgmt }) => {
-  const baiClient = useSuspendedBackendaiClient();
+  mode?: 'simple-elapsed' | 'detail';
+}> = ({ sessionFrgmt, mode = 'detail' }) => {
   const { t } = useTranslation();
   const session = useFragment(
     graphql`
@@ -25,25 +26,27 @@ const SessionReservation: React.FC<{
   );
   return (
     <>
-      {dayjs(session.created_at).format('lll')}
+      {mode !== 'simple-elapsed' && dayjs(session.created_at).format('lll')}
       <BAIIntervalView
+        key={session.id}
         callback={() => {
           return session?.created_at
-            ? baiClient.utils.elapsedTime(
-                session.created_at,
-                session?.terminated_at,
-              )
+            ? formatDurationAsDays(session.created_at, session?.terminated_at)
             : '-';
         }}
         delay={1000}
-        render={(intervalValue) => (
-          <DoubleTag
-            values={[
-              { label: t('session.ElapsedTime') },
-              { label: intervalValue },
-            ]}
-          />
-        )}
+        render={(intervalValue) =>
+          mode === 'simple-elapsed' ? (
+            intervalValue
+          ) : (
+            <DoubleTag
+              values={[
+                { label: t('session.ElapsedTime') },
+                { label: intervalValue },
+              ]}
+            />
+          )
+        }
       />
     </>
   );
diff --git a/react/src/components/ComputeSessionNodeItems/SessionStatusTag.tsx b/react/src/components/ComputeSessionNodeItems/SessionStatusTag.tsx
index a7213ac526..f6b9cc85f7 100644
--- a/react/src/components/ComputeSessionNodeItems/SessionStatusTag.tsx
+++ b/react/src/components/ComputeSessionNodeItems/SessionStatusTag.tsx
@@ -12,6 +12,7 @@ import { useFragment } from 'react-relay';
 
 interface SessionStatusTagProps {
   sessionFrgmt?: SessionStatusTagFragment$key | null;
+  showInfo?: boolean;
 }
 const statusTagColor = {
   //prepare
@@ -51,6 +52,7 @@ const statusInfoTagColor = {
 };
 const SessionStatusTag: React.FC<SessionStatusTagProps> = ({
   sessionFrgmt,
+  showInfo,
 }) => {
   const session = useFragment(
     graphql`
@@ -66,7 +68,7 @@ const SessionStatusTag: React.FC<SessionStatusTagProps> = ({
   const { token } = theme.useToken();
 
   return session ? (
-    _.isEmpty(session.status_info) ? (
+    _.isEmpty(session.status_info) || !showInfo ? (
       <Tag
         color={
           session.status ? _.get(statusTagColor, session.status) : undefined
diff --git a/react/src/components/ComputeSessionNodeItems/TerminateSessionModal.tsx b/react/src/components/ComputeSessionNodeItems/TerminateSessionModal.tsx
index c9cef41539..2c73f53d5a 100644
--- a/react/src/components/ComputeSessionNodeItems/TerminateSessionModal.tsx
+++ b/react/src/components/ComputeSessionNodeItems/TerminateSessionModal.tsx
@@ -200,6 +200,7 @@ const TerminateSessionModal: React.FC<TerminateSessionModalProps> = ({
     `,
     sessionFrgmt,
   );
+
   const [isForce, setIsForce] = useState(false);
   const userRole = useCurrentUserRole();
 
diff --git a/react/src/components/SessionDetailContent.tsx b/react/src/components/SessionDetailContent.tsx
index f2da9038ac..0da1a59108 100644
--- a/react/src/components/SessionDetailContent.tsx
+++ b/react/src/components/SessionDetailContent.tsx
@@ -169,7 +169,7 @@ const SessionDetailContent: React.FC<{
           label={t('session.Status')}
           contentStyle={{ display: 'flex', gap: token.marginSM }}
         >
-          <SessionStatusTag sessionFrgmt={session} />
+          <SessionStatusTag sessionFrgmt={session} showInfo />
           {/* <Button type="text" icon={<TriangleAlertIcon />} /> */}
         </Descriptions.Item>
         <Descriptions.Item label={t('session.SessionType')}>
diff --git a/react/src/components/SessionNodes.tsx b/react/src/components/SessionNodes.tsx
new file mode 100644
index 0000000000..3aa58f0021
--- /dev/null
+++ b/react/src/components/SessionNodes.tsx
@@ -0,0 +1,134 @@
+import BAILink from './BAILink';
+import BAITable from './BAITable';
+import SessionOccupiedSlot from './ComputeSessionNodeItems/SessionOccupiedSlot';
+import SessionReservation from './ComputeSessionNodeItems/SessionReservation';
+import SessionStatusTag from './ComputeSessionNodeItems/SessionStatusTag';
+import SessionDetailDrawer from './SessionDetailDrawer';
+import { SessionNodesFragment$key } from './__generated__/SessionNodesFragment.graphql';
+import { TableProps } from 'antd/lib';
+import graphql from 'babel-plugin-relay/macro';
+import React, { useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import { useFragment } from 'react-relay';
+
+interface SessionNodesProps extends Omit<TableProps, 'dataSource' | 'columns'> {
+  sessionsFrgmt: SessionNodesFragment$key;
+}
+const SessionNodes: React.FC<SessionNodesProps> = ({
+  sessionsFrgmt,
+  ...tableProps
+}) => {
+  const { t } = useTranslation();
+  const [selectedSessionId, setSelectedSessionId] = useState<string>();
+
+  const sessions = useFragment(
+    graphql`
+      fragment SessionNodesFragment on ComputeSessionNode @relay(plural: true) {
+        id
+        row_id
+        name
+        ...SessionStatusTagFragment
+        ...SessionReservationFragment
+        ...SessionOccupiedSlotFragment
+      }
+    `,
+    sessionsFrgmt,
+  );
+
+  return (
+    <>
+      <BAITable
+        resizable
+        rowKey={(record) => record.rowId}
+        dataSource={sessions}
+        scroll={{ x: 'max-content' }}
+        columns={[
+          {
+            key: 'name',
+            title: t('session.SessionName'),
+            dataIndex: 'name',
+            render: (name: string, session) => {
+              return (
+                <BAILink
+                  to={'#'}
+                  type="hover"
+                  onClick={(e) => {
+                    session.row_id && setSelectedSessionId(session.row_id);
+                  }}
+                >
+                  {name}
+                </BAILink>
+              );
+            },
+            sorter: true,
+          },
+          {
+            key: 'status',
+            title: t('session.Status'),
+            dataIndex: 'status',
+            render: (status: string, session) => {
+              // @ts-expect-error
+              return <SessionStatusTag sessionFrgmt={session} />;
+            },
+          },
+          {
+            key: 'utils',
+            title: t('session.Utilization'),
+          },
+          {
+            key: 'accelerator',
+            title: t('session.launcher.AIAccelerator'),
+            render: (__, session) => {
+              return (
+                <SessionOccupiedSlot
+                  // @ts-expect-error
+                  sessionFrgmt={session}
+                  type="accelerator"
+                />
+              );
+            },
+          },
+          {
+            key: 'cpu',
+            title: t('session.launcher.CPU'),
+            render: (__, session) => {
+              // @ts-expect-error
+              return <SessionOccupiedSlot sessionFrgmt={session} type="cpu" />;
+            },
+          },
+          {
+            key: 'mem',
+            title: t('session.launcher.Memory'),
+            render: (__, session) => {
+              // @ts-expect-error
+              return <SessionOccupiedSlot sessionFrgmt={session} type="mem" />;
+            },
+          },
+          {
+            key: 'elapsedTime',
+            title: t('session.ElapsedTime'),
+            render: (__, session) => {
+              return (
+                <SessionReservation
+                  mode="simple-elapsed"
+                  // @ts-expect-error
+                  sessionFrgmt={session}
+                />
+              );
+            },
+          },
+        ]}
+        {...tableProps}
+      />
+      <SessionDetailDrawer
+        open={!selectedSessionId}
+        sessionId={selectedSessionId}
+        onClose={() => {
+          setSelectedSessionId(undefined);
+        }}
+      />
+    </>
+  );
+};
+
+export default SessionNodes;
diff --git a/react/src/helper/index.tsx b/react/src/helper/index.tsx
index e6062ac847..57de0bcf88 100644
--- a/react/src/helper/index.tsx
+++ b/react/src/helper/index.tsx
@@ -3,6 +3,7 @@ import { Image } from '../components/ImageEnvironmentSelectFormItems';
 import { EnvironmentImage } from '../components/ImageList';
 import { useSuspendedBackendaiClient } from '../hooks';
 import { SorterResult } from 'antd/es/table/interface';
+import dayjs from 'dayjs';
 import { Duration } from 'dayjs/plugin/duration';
 import { TFunction } from 'i18next';
 import _ from 'lodash';
@@ -452,3 +453,21 @@ export function formatDuration(duration: Duration, t: TFunction) {
     .filter(Boolean)
     .join(' ');
 }
+
+export function formatDurationAsDays(
+  start: string,
+  end?: string | null,
+  dayLabel: string = 'd ',
+): string {
+  const startTime = dayjs(start);
+  const endTime = end ? dayjs(end) : dayjs();
+
+  const diff = dayjs.duration(endTime.diff(startTime));
+
+  const asDays = Math.floor(diff.asDays());
+  const hours = diff.hours().toString().padStart(2, '0');
+  const minutes = diff.minutes().toString().padStart(2, '0');
+  const seconds = diff.seconds().toString().padStart(2, '0');
+
+  return `${asDays ? `${asDays}${dayLabel}` : ''}${hours}:${minutes}:${seconds}`;
+}
diff --git a/react/src/hooks/reactPaginationQueryOptions.tsx b/react/src/hooks/reactPaginationQueryOptions.tsx
index 0359904054..f1f0e3b0e0 100644
--- a/react/src/hooks/reactPaginationQueryOptions.tsx
+++ b/react/src/hooks/reactPaginationQueryOptions.tsx
@@ -281,6 +281,7 @@ export const useBAIPaginationQueryOptions = ({
 interface BAIPaginationOption {
   limit: number;
   offset: number;
+  first?: number;
   // filter?: string;
   // order?: string;
 }
@@ -297,13 +298,16 @@ export const useBAIPaginationOptionState = (
 ): {
   baiPaginationOption: BAIPaginationOption;
   tablePaginationOption: AntdBasicPaginationOption;
-  setTablePaginationOption: (pagination: AntdBasicPaginationOption) => void;
+  setTablePaginationOption: (
+    pagination: Partial<AntdBasicPaginationOption>,
+  ) => void;
 } => {
   const [options, setOptions] =
     useState<AntdBasicPaginationOption>(initialOptions);
   return {
     baiPaginationOption: {
       limit: options.pageSize,
+      first: options.pageSize,
       offset:
         options.current > 1 ? (options.current - 1) * options.pageSize : 0,
     },
diff --git a/react/src/pages/ComputeSessionListPage.tsx b/react/src/pages/ComputeSessionListPage.tsx
new file mode 100644
index 0000000000..bdbce1653e
--- /dev/null
+++ b/react/src/pages/ComputeSessionListPage.tsx
@@ -0,0 +1,250 @@
+import BAILink from '../components/BAILink';
+import BAIPropertyFilter, {
+  mergeFilterValues,
+} from '../components/BAIPropertyFilter';
+import Flex from '../components/Flex';
+import SessionNodes from '../components/SessionNodes';
+import { filterNonNullItems, transformSorterToOrderString } from '../helper';
+import { useBAIPaginationOptionState } from '../hooks/reactPaginationQueryOptions';
+import { useCurrentProjectValue } from '../hooks/useCurrentProject';
+import { ComputeSessionListPageQuery } from './__generated__/ComputeSessionListPageQuery.graphql';
+import { LoadingOutlined } from '@ant-design/icons';
+import { Badge, Button, Card, Radio, Tabs, theme } from 'antd';
+import graphql from 'babel-plugin-relay/macro';
+import _ from 'lodash';
+import { useState, useTransition } from 'react';
+import { useTranslation } from 'react-i18next';
+import { useLazyLoadQuery } from 'react-relay';
+import {
+  JsonParam,
+  StringParam,
+  useQueryParams,
+  withDefault,
+} from 'use-query-params';
+
+type TypeFilterType = 'all' | 'interactive' | 'batch' | 'inference' | 'system';
+const ComputeSessionList = () => {
+  const currentProject = useCurrentProjectValue();
+
+  const { t } = useTranslation();
+  const { token } = theme.useToken();
+
+  const {
+    baiPaginationOption,
+    tablePaginationOption,
+    setTablePaginationOption,
+  } = useBAIPaginationOptionState({
+    current: 1,
+    pageSize: 10,
+  });
+  const [isPendingPageChange, startPageChangeTransition] = useTransition();
+  const [isPendingFilterChange, startFilterChangeTransition] = useTransition();
+
+  const [query, setQuery] = useQueryParams({
+    order: StringParam,
+    filterString: StringParam,
+    typeFilterType: withDefault(StringParam, 'all'),
+    runningFilterType: withDefault(StringParam, 'running'),
+  });
+
+  const { order, filterString, typeFilterType, runningFilterType } = query;
+
+  const typeFilter =
+    typeFilterType === 'all' ? undefined : `type == "${typeFilterType}"`;
+
+  const statusFilter =
+    runningFilterType === 'running'
+      ? 'status != "TERMINATED" & status != "CANCELLED"'
+      : 'status == "TERMINATED" | status == "CANCELLED"';
+
+  const { compute_session_nodes, allRunningSessionForCount } =
+    useLazyLoadQuery<ComputeSessionListPageQuery>(
+      graphql`
+        query ComputeSessionListPageQuery(
+          $projectId: UUID!
+          $first: Int = 20
+          $offset: Int = 0
+          $filter: String
+          $order: String
+          $runningTypeFilter: String!
+        ) {
+          compute_session_nodes(
+            project_id: $projectId
+            first: $first
+            offset: $offset
+            filter: $filter
+            order: $order
+          ) {
+            edges @required(action: THROW) {
+              node @required(action: THROW) {
+                id
+                ...SessionNodesFragment
+              }
+            }
+            count
+          }
+          allRunningSessionForCount: compute_session_nodes(
+            project_id: $projectId
+            first: 0
+            offset: 0
+            filter: $runningTypeFilter
+          ) {
+            count
+          }
+        }
+      `,
+      {
+        projectId: currentProject.id,
+        offset: baiPaginationOption.offset,
+        first: baiPaginationOption.first,
+        filter: mergeFilterValues([statusFilter, filterString, typeFilter]),
+        order,
+        runningTypeFilter: 'status != "TERMINATED" & status != "CANCELLED"',
+      },
+      {
+        fetchPolicy: 'network-only',
+      },
+    );
+
+  return (
+    <>
+      {/* TODO: add legacy opener */}
+      {/* <SessionDetailAndContainerLogOpenerForLegacy /> */}
+      <Card
+        bordered={false}
+        title={t('webui.menu.Sessions')}
+        extra={[
+          <BAILink to={'/session/start'}>
+            <Button type="primary">Start Session</Button>
+          </BAILink>,
+        ]}
+        styles={{
+          header: {
+            borderBottom: 'none',
+          },
+          body: {
+            paddingTop: 0,
+          },
+        }}
+      >
+        <Tabs
+          type="card"
+          activeKey={typeFilterType}
+          onChange={(key) => {
+            startFilterChangeTransition(() => {
+              setQuery({ typeFilterType: key as TypeFilterType });
+              setTablePaginationOption({ current: 1 });
+            });
+          }}
+          items={_.map(
+            {
+              all: t('general.All'),
+              interactive: t('session.Interactive'),
+              batch: t('session.Batch'),
+              inference: t('session.Inference'),
+              system: t('session.System'),
+            },
+            (label, key) => ({
+              key,
+              label: (
+                <Flex justify="center" gap={10}>
+                  {label}
+                  {key === 'all' && (
+                    <Badge
+                      count={allRunningSessionForCount?.count}
+                      color={token.colorPrimary}
+                      size="small"
+                      showZero
+                      style={{
+                        paddingRight: token.paddingXS,
+                        paddingLeft: token.paddingXS,
+                        fontSize: 10,
+                      }}
+                    />
+                  )}
+                  {/*  */}
+                </Flex>
+              ),
+            }),
+          )}
+        />
+        <Flex direction="column" align="stretch" gap={'sm'}>
+          <Flex gap={'sm'} align="start">
+            <Radio.Group
+              optionType="button"
+              value={runningFilterType}
+              onChange={(e) => {
+                startFilterChangeTransition(() => {
+                  setQuery({ runningFilterType: e.target.value });
+                });
+              }}
+              options={[
+                {
+                  label: 'Running',
+                  value: 'running',
+                },
+                {
+                  label: 'Finished',
+                  value: 'finished',
+                },
+              ]}
+            />
+            <BAIPropertyFilter
+              filterProperties={[
+                {
+                  key: 'name',
+                  propertyLabel: t('session.SessionName'),
+                  type: 'string',
+                },
+              ]}
+              value={filterString || undefined}
+              onChange={(value) => {
+                startFilterChangeTransition(() => {
+                  setQuery({ filterString: value });
+                  setTablePaginationOption({ current: 1 });
+                });
+              }}
+            />
+          </Flex>
+          <SessionNodes
+            rowSelection={{
+              type: 'checkbox',
+              // onChange: (selectedRowKeys, selectedRows) => {
+              //   console.log(
+              //     `selectedRowKeys: ${selectedRowKeys}`,
+              //     'selectedRows: ',
+              //     selectedRows,
+              //   );
+              // },
+            }}
+            sessionsFrgmt={filterNonNullItems(
+              compute_session_nodes?.edges.map((e) => e?.node),
+            )}
+            pagination={{
+              pageSize: tablePaginationOption.pageSize,
+              current: tablePaginationOption.current,
+              total: compute_session_nodes?.count ?? 0,
+              // showTotal: (total) => {
+              //   return total;
+              // },
+            }}
+            loading={{
+              spinning: isPendingPageChange || isPendingFilterChange,
+              indicator: <LoadingOutlined />,
+            }}
+            onChange={({ current, pageSize }, filters, sorter) => {
+              startPageChangeTransition(() => {
+                if (_.isNumber(current) && _.isNumber(pageSize)) {
+                  setTablePaginationOption({ current, pageSize });
+                }
+                setQuery({ order: transformSorterToOrderString(sorter) });
+              });
+            }}
+          />
+        </Flex>
+      </Card>
+    </>
+  );
+};
+
+export default ComputeSessionList;
diff --git a/resources/theme.json b/resources/theme.json
index 1b2c28a8b9..d528988fad 100644
--- a/resources/theme.json
+++ b/resources/theme.json
@@ -14,7 +14,7 @@
         "borderRadiusSM": 1
       },
       "Table": {
-        "headerBorderRadius": 0
+        "headerBg": "#E3E3E3"
       },
       "Layout": {
         "lightSiderBg": "#FFF",