diff --git a/package-lock.json b/package-lock.json
index 4ea38f814b7d809d9fff357f22638c48451e8b7c..d2bc55f33aa424948d6ba13f87b807af622bbfa2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -20,6 +20,7 @@
         "@testing-library/user-event": "^12.6.0",
         "ansi-to-html": "^0.7.2",
         "isomorphic-fetch": "^3.0.0",
+        "javascript-time-ago": "^2.5.9",
         "moment": "^2.29.1",
         "node-request-interceptor": "^0.6.3",
         "notistack": "^3.0.1",
@@ -20567,6 +20568,14 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/javascript-time-ago": {
+      "version": "2.5.9",
+      "resolved": "https://registry.npmjs.org/javascript-time-ago/-/javascript-time-ago-2.5.9.tgz",
+      "integrity": "sha512-pQ8mNco/9g9TqWXWWjP0EWl6i/lAQScOyEeXy5AB+f7MfLSdgyV9BJhiOD1zrIac/lrxPYOWNbyl/IW8CW5n0A==",
+      "dependencies": {
+        "relative-time-format": "^1.1.6"
+      }
+    },
     "node_modules/jest": {
       "version": "26.6.3",
       "resolved": "https://registry.npmjs.org/jest/-/jest-26.6.3.tgz",
@@ -31976,6 +31985,11 @@
         "node": ">= 0.10"
       }
     },
+    "node_modules/relative-time-format": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/relative-time-format/-/relative-time-format-1.1.6.tgz",
+      "integrity": "sha512-aCv3juQw4hT1/P/OrVltKWLlp15eW1GRcwP1XdxHrPdZE9MtgqFpegjnTjLhi2m2WI9MT/hQQtE+tjEWG1hgkQ=="
+    },
     "node_modules/remark-external-links": {
       "version": "8.0.0",
       "resolved": "https://registry.npmjs.org/remark-external-links/-/remark-external-links-8.0.0.tgz",
@@ -55363,6 +55377,14 @@
         "iterate-iterator": "^1.0.1"
       }
     },
+    "javascript-time-ago": {
+      "version": "2.5.9",
+      "resolved": "https://registry.npmjs.org/javascript-time-ago/-/javascript-time-ago-2.5.9.tgz",
+      "integrity": "sha512-pQ8mNco/9g9TqWXWWjP0EWl6i/lAQScOyEeXy5AB+f7MfLSdgyV9BJhiOD1zrIac/lrxPYOWNbyl/IW8CW5n0A==",
+      "requires": {
+        "relative-time-format": "^1.1.6"
+      }
+    },
     "jest": {
       "version": "26.6.3",
       "resolved": "https://registry.npmjs.org/jest/-/jest-26.6.3.tgz",
@@ -64049,6 +64071,11 @@
       "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==",
       "dev": true
     },
+    "relative-time-format": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/relative-time-format/-/relative-time-format-1.1.6.tgz",
+      "integrity": "sha512-aCv3juQw4hT1/P/OrVltKWLlp15eW1GRcwP1XdxHrPdZE9MtgqFpegjnTjLhi2m2WI9MT/hQQtE+tjEWG1hgkQ=="
+    },
     "remark-external-links": {
       "version": "8.0.0",
       "resolved": "https://registry.npmjs.org/remark-external-links/-/remark-external-links-8.0.0.tgz",
diff --git a/package.json b/package.json
index c3551deb8a8cebd58c3ed98be1a11e49dc7ee32b..1c67920cb4487f177b29d3d74cc55cb601619d7a 100644
--- a/package.json
+++ b/package.json
@@ -16,6 +16,7 @@
     "@testing-library/user-event": "^12.6.0",
     "ansi-to-html": "^0.7.2",
     "isomorphic-fetch": "^3.0.0",
+    "javascript-time-ago": "^2.5.9",
     "moment": "^2.29.1",
     "node-request-interceptor": "^0.6.3",
     "notistack": "^3.0.1",
diff --git a/src/components/IOC/GitRefLink/GitRefLink.js b/src/components/IOC/GitRefLink/GitRefLink.js
index aed0d253917c23452533c0a93cfc37b84f6503dd..54e07f242e69cc9218757ad18a3e741b06f343d1 100644
--- a/src/components/IOC/GitRefLink/GitRefLink.js
+++ b/src/components/IOC/GitRefLink/GitRefLink.js
@@ -3,8 +3,9 @@
  * Component providing link (and tag) to gitlab
  */
 import React from "react";
-import { Typography, Link as MuiLink } from "@mui/material";
+import { Typography, Link as MuiLink, Stack } from "@mui/material";
 import { string } from "prop-types";
+import LaunchIcon from "@mui/icons-material/Launch";
 
 const propTypes = {
   /** String containing url to gitlab template */
@@ -13,7 +14,25 @@ const propTypes = {
   revision: string
 };
 
-export default function GitRefLink({ url, revision }) {
+const defaultRenderLinkContents = (revision) => {
+  return (
+    <Stack
+      flexDirection="row"
+      alignItems="center"
+      gap={0.5}
+    >
+      {revision}
+      <LaunchIcon fontSize="small" />
+    </Stack>
+  );
+};
+
+export default function GitRefLink({
+  url,
+  revision,
+  renderLinkContents = defaultRenderLinkContents,
+  LinkProps
+}) {
   // if no git reference has been entered
   if (!url || url.trim === "") {
     return <></>;
@@ -39,8 +58,10 @@ export default function GitRefLink({ url, revision }) {
         target="_blank"
         rel="noreferrer"
         underline="hover"
+        aria-label={`External Git Link, revision ${revision}`}
+        {...LinkProps}
       >
-        {revision}
+        {renderLinkContents(revision)}
       </MuiLink>
     </Typography>
   );
diff --git a/src/components/IOC/IOCIcons/IOCIcons.js b/src/components/IOC/IOCIcons/IOCIcons.js
index 450b88ee13ed3dac6b5d6e7b2c3fe770c42e4cc4..2cf9d58319aefe12a5dc2e63708e5655f4eff31f 100644
--- a/src/components/IOC/IOCIcons/IOCIcons.js
+++ b/src/components/IOC/IOCIcons/IOCIcons.js
@@ -1,5 +1,5 @@
 import React from "react";
-import { Tooltip, Typography, useTheme } from "@mui/material";
+import { Typography, useTheme } from "@mui/material";
 import {
   Brightness1,
   Cancel,
@@ -12,6 +12,7 @@ import {
 } from "@mui/icons-material";
 import Popover from "../../common/Popover";
 import { AlertBannerList } from "@ess-ics/ce-ui-common";
+import LabeledIcon from "../../common/LabeledIcon/LabeledIcon";
 
 function AlertMessagesPopoverContents({ title, alerts }) {
   // Filter out INFO level alerts
@@ -48,27 +49,27 @@ export function IOCStatusIcon({ ioc }) {
   const iconConfig = {
     active: {
       title: "Active",
-      icon: <Brightness1 title="Active" />
+      icon: Brightness1
     },
     disabled: {
       title: "Disabled",
-      icon: <Cancel title="Disabled" />
+      icon: Cancel
     },
     alert: {
       title: "Alert",
-      icon: <Error title="Alert" />
+      icon: Error
     },
     inactive: {
       title: "Inactive",
-      icon: <StopCircle title="Inactive" />
+      icon: StopCircle
     },
     "inactive alert": {
       title: "Alert",
-      icon: <ErrorOutline title="Active" />
+      icon: ErrorOutline
     },
     null: {
       title: "Unknown",
-      icon: <HelpOutline title="Unknown" />
+      icon: HelpOutline
     }
   };
 
@@ -111,7 +112,13 @@ export function IOCStatusIcon({ ioc }) {
   }
 
   const iconTitle = iconConfig[status].title;
-  const statusIcon = iconConfig[status].icon;
+  const statusIcon = (
+    <LabeledIcon
+      label={iconTitle}
+      Icon={iconConfig[status].icon}
+      labelPosition="none"
+    />
+  );
 
   return (
     <div>
@@ -148,7 +155,11 @@ export function IOCStatusIcon({ ioc }) {
   );
 }
 
-export function CommandTypeIcon({ type, colorStyle = "colors" }) {
+export function CommandTypeIcon({
+  type,
+  colorStyle = "colors",
+  labelPosition = "tooltip"
+}) {
   const theme = useTheme();
 
   const commandTypeColors = {
@@ -169,24 +180,25 @@ export function CommandTypeIcon({ type, colorStyle = "colors" }) {
   const commandTypeIcons = {
     start: {
       title: "Set to active",
-      icon: <PlayCircleFilled />
+      icon: PlayCircleFilled
     },
     stop: {
       title: "Set to inactive",
-      icon: <PauseCircleFilled />
+      icon: PauseCircleFilled
     }
   };
 
   const iconStyle = { fill: colorConfig[colorStyle][type.toLowerCase()] };
   const iconTitle = commandTypeIcons[type.toLowerCase()].title;
-  const statusIcon = commandTypeIcons[type.toLowerCase()].icon;
+  const StatusIcon = commandTypeIcons[type.toLowerCase()].icon;
 
   return (
-    <Tooltip
-      title={iconTitle}
-      style={iconStyle}
-    >
-      {statusIcon}
-    </Tooltip>
+    <LabeledIcon
+      label={iconTitle}
+      LabelProps={{ nowrap: true }}
+      labelPosition={labelPosition}
+      Icon={StatusIcon}
+      IconProps={{ style: { iconStyle } }}
+    />
   );
 }
diff --git a/src/components/IOC/IOCTable/IOCTable.spec.js b/src/components/IOC/IOCTable/IOCTable.spec.js
index c2606c24e04f4febd24a9ad1bba543bb82332040..bac3b2bb9d0ba8084fb79be4987cfd6909cd8dfb 100644
--- a/src/components/IOC/IOCTable/IOCTable.spec.js
+++ b/src/components/IOC/IOCTable/IOCTable.spec.js
@@ -39,7 +39,7 @@ describe("HostTable", () => {
         .each(($el, index) => {
           if (index === 0) {
             const iconTitle = firstRowData[index];
-            cy.wrap($el).find(`svg[title=${iconTitle}]`);
+            cy.wrap($el).findByRole("img", { name: iconTitle });
           } else {
             cy.wrap($el)
               .find("p")
diff --git a/src/components/Job/JobDetails.js b/src/components/Job/JobDetails.js
index 22c817790daee504b5e7876df4e2d446e4af95bc..7d683b756444a7c1692811b9e5ca5890afb95ee4 100644
--- a/src/components/Job/JobDetails.js
+++ b/src/components/Job/JobDetails.js
@@ -10,8 +10,7 @@ import {
 import {
   KeyValueTable,
   SimpleAccordion,
-  AlertBannerList,
-  Stepper
+  AlertBannerList
 } from "@ess-ics/ce-ui-common";
 import { JobBadge } from "./JobBadge";
 import { DeploymentJobOutput } from "../deployments/DeploymentJobOutput";
@@ -20,21 +19,7 @@ import { formatDate } from "../common/Helper";
 import GitRefLink from "../IOC/GitRefLink";
 import AccessControl from "../auth/AccessControl";
 import { AWXJobDetails } from "../../api/DataTypes";
-
-const STATUS = {
-  queued: {
-    label: "Queued",
-    alertType: "info"
-  },
-  running: {
-    label: "Running",
-    alertType: "info"
-  },
-  successful: {
-    label: "Completed",
-    alertType: "success"
-  }
-};
+import { JobStatusStepper } from "./JobStatus";
 
 function createAlert(operation, job) {
   const jobDetails = new AWXJobDetails(operation.type, job);
@@ -117,17 +102,6 @@ export function JobDetails({ operation, job }) {
       : "-"
   };
 
-  const normalizedStatus = job?.status?.toLowerCase();
-
-  const currentStep = Object.keys(STATUS).indexOf(normalizedStatus);
-  var activeStep = STATUS[normalizedStatus] ? currentStep + 1 : currentStep;
-  const jobFailed = job?.status?.toLowerCase() === "failed";
-
-  // to show the correct failed step for an already finished operation
-  if (jobFailed) {
-    activeStep = operation?.startTime ? 1 : 0;
-  }
-
   return (
     <Grid
       container
@@ -165,15 +139,7 @@ export function JobDetails({ operation, job }) {
       >
         <Card>
           <CardContent>
-            <div>
-              {job && (
-                <Stepper
-                  steps={Object.values(STATUS).map((it) => it.label)}
-                  activeStep={activeStep}
-                  isActiveStepFailed={jobFailed}
-                />
-              )}
-            </div>
+            <div>{job && <JobStatusStepper {...{ job, operation }} />}</div>
           </CardContent>
         </Card>
       </Grid>
diff --git a/src/components/Job/JobIcons.js b/src/components/Job/JobIcons.js
index 20b4b48cb9f41160dfbc27fb74068133a2ab89b5..0f9ece62909646a8d94565f615b73384b2d252b4 100644
--- a/src/components/Job/JobIcons.js
+++ b/src/components/Job/JobIcons.js
@@ -9,14 +9,18 @@ export function JobStatusIcon({ status }) {
   return <DeploymentStatusIcon status={status} />;
 }
 
-export function JobTypeIcon({ type, colorStyle }) {
+export function JobTypeIcon({ type, colorStyle, labelPosition }) {
   const icon = ["START", "STOP"].includes(type) ? (
     <CommandTypeIcon
       type={type}
       colorStyle={colorStyle}
+      labelPosition={labelPosition}
     />
   ) : (
-    <DeploymentTypeIcon type={type} />
+    <DeploymentTypeIcon
+      type={type}
+      labelPosition={labelPosition}
+    />
   );
 
   return icon;
diff --git a/src/components/Job/JobStatus.js b/src/components/Job/JobStatus.js
new file mode 100644
index 0000000000000000000000000000000000000000..eca307f5ec533e05684f12edf422bad2b80571ca
--- /dev/null
+++ b/src/components/Job/JobStatus.js
@@ -0,0 +1,90 @@
+import { Stepper } from "@ess-ics/ce-ui-common";
+import React from "react";
+import {
+  RotateRightOutlined,
+  CheckCircleOutline,
+  ErrorOutline,
+  HelpOutline
+} from "@mui/icons-material";
+import LabeledIcon from "../common/LabeledIcon";
+import { theme } from "../../style/Theme";
+
+const STEPPER_STATUS = {
+  queued: {
+    label: "Queued",
+    alertType: "info",
+    icon: RotateRightOutlined,
+    color: theme.palette.status.progress
+  },
+  running: {
+    label: "Running",
+    alertType: "info",
+    icon: RotateRightOutlined,
+    color: theme.palette.status.progress
+  },
+  successful: {
+    label: "Completed",
+    alertType: "success",
+    icon: CheckCircleOutline,
+    color: theme.palette.status.ok
+  }
+};
+
+const STATUS = {
+  ...STEPPER_STATUS,
+  failed: {
+    label: "Error",
+    alertType: "error",
+    icon: ErrorOutline,
+    color: theme.palette.status.fail
+  },
+  unknown: {
+    label: "Unknown",
+    alertType: "info",
+    icon: HelpOutline,
+    color: theme.palette.disabled
+  }
+};
+
+export const JobStatusStepper = ({ job, operation }) => {
+  const normalizedStatus = job?.status?.toLowerCase();
+
+  const currentStep = Object.keys(STEPPER_STATUS).indexOf(normalizedStatus);
+  let activeStep = STEPPER_STATUS[normalizedStatus]
+    ? currentStep + 1
+    : currentStep;
+  const jobFailed = job?.status?.toLowerCase() === "failed";
+
+  // to show the correct failed step for an already finished operation
+  if (jobFailed) {
+    activeStep = operation?.startTime ? 1 : 0;
+  }
+
+  return (
+    <Stepper
+      steps={Object.values(STEPPER_STATUS).map((it) => it.label)}
+      activeStep={activeStep}
+      isActiveStepFailed={jobFailed}
+    />
+  );
+};
+
+export const JobStatusIcon = ({ job }) => {
+  const activeStep = STATUS[job?.status?.toLowerCase()] ?? STATUS.unknown;
+
+  return (
+    <LabeledIcon
+      label={activeStep.label}
+      labelPosition="right"
+      LabelProps={{
+        color: activeStep.alertType === "error" ? "status.fail" : "inherit"
+      }}
+      Icon={activeStep.icon}
+      IconProps={{
+        style: {
+          fill: activeStep.color
+        }
+      }}
+    />
+  );
+};
diff --git a/src/components/Job/JobTable.js b/src/components/Job/JobTable.js
deleted file mode 100644
index 42d3f372fb5946dccfdde903674ba4fcd8abf389..0000000000000000000000000000000000000000
--- a/src/components/Job/JobTable.js
+++ /dev/null
@@ -1,103 +0,0 @@
-import React from "react";
-import { Table } from "@ess-ics/ce-ui-common";
-import { Box, Grid } from "@mui/material";
-import { EllipsisTextLink, noWrapText } from "../common/Helper";
-import { JobTypeIcon } from "./JobIcons";
-import { formatDate } from "../common/Helper";
-
-const jobLogColumns = [
-  {
-    field: "type",
-    headerName: "Type",
-    headerAlign: "center",
-    align: "center",
-    maxWidth: 60
-  },
-  { field: "ioc", headerName: "IOC name", minWidth: 120 },
-  { field: "version", headerName: "Revision", minWidth: 120 },
-  { field: "host", headerName: "Host", minWidth: 120 },
-  { field: "user", headerName: "User", minWidth: 100 },
-  {
-    field: "start",
-    headerName: "Time",
-    minWidth: 120,
-    sortable: false,
-    headerAlign: "right",
-    align: "right"
-  }
-];
-
-const userPageJobLogColumns = [
-  ...jobLogColumns.filter((it) => it.field !== "user")
-];
-
-function createTableRow(job, colorStyle) {
-  return {
-    id: job.id,
-    type: (
-      <Grid
-        container
-        direction="column"
-        justifyContent="center"
-        alignItems="center"
-      >
-        <JobTypeIcon
-          type={job.type}
-          colorStyle={colorStyle}
-        />
-      </Grid>
-    ),
-    ioc: (
-      <EllipsisTextLink
-        text={job.iocName}
-        href={`/iocs/${job.iocId}`}
-      />
-    ),
-    version: job.gitReference,
-    host: job.host?.hostName ? (
-      <EllipsisTextLink
-        text={job.host?.hostName}
-        href={`/hosts/${job?.host?.externalHostId}`}
-      />
-    ) : null,
-    user: (
-      <EllipsisTextLink
-        text={job.createdBy}
-        href={`/user/${job.createdBy}`}
-      />
-    ),
-    start: noWrapText(formatDate(job.createdAt))
-  };
-}
-
-function createTableRowJobLog(job) {
-  return createTableRow(job, "black");
-}
-
-export function JobTable({
-  jobs,
-  rowType = "jobLog",
-  pagination,
-  onPage,
-  loading
-}) {
-  const tableTypeSpecifics = {
-    jobLog: [jobLogColumns, createTableRowJobLog],
-    userPageJobLog: [userPageJobLogColumns, createTableRowJobLog]
-  };
-
-  const [columns, createRow] = tableTypeSpecifics[rowType];
-
-  return (
-    <Box sx={{ pt: 2 }}>
-      <Table
-        columns={columns}
-        rows={jobs?.map((job) => createRow(job))}
-        pagination={pagination}
-        onPage={onPage}
-        loading={loading}
-        disableHover
-      />
-    </Box>
-  );
-}
diff --git a/src/components/Job/JobTable/JobGitRefLink.js b/src/components/Job/JobTable/JobGitRefLink.js
new file mode 100644
index 0000000000000000000000000000000000000000..5fe2a6a65e36f923d6650ec741c639f1ef7be491
--- /dev/null
+++ b/src/components/Job/JobTable/JobGitRefLink.js
@@ -0,0 +1,49 @@
+import React, { useContext, useMemo } from "react";
+import GitRefLink from "../../IOC/GitRefLink/GitRefLink";
+import { apiContext } from "../../../api/DeployApi";
+import { useAPIMethod } from "@ess-ics/ce-ui-common";
+import { Skeleton } from "@mui/material";
+
+export const JobGitRefLink = ({ job }) => {
+  const client = useContext(apiContext);
+  const projectParams = useMemo(
+    () => ({
+      project_id: job?.gitProjectId
+    }),
+    [job]
+  );
+
+  const { value: project } = useAPIMethod({
+    fcn: client.apis.Git.gitProjectDetails,
+    params: projectParams
+  });
+
+  const shortRefParams = useMemo(
+    () => ({
+      project_id: job?.gitProjectId,
+      reference: job?.gitReference
+    }),
+    [job]
+  );
+  const { value: commits } = useAPIMethod({
+    fcn: client.apis.Git.listTagsAndCommitIds,
+    params: shortRefParams
+  });
+
+  if (!project || !commits) {
+    return <Skeleton width={100} />;
+  }
+
+  const gitRef = commits?.at(0)?.shortReference ?? job.gitReference;
+
+  return (
+    <GitRefLink
+      url={project?.projectUrl}
+      revision={gitRef}
+      renderLinkContents={(revision) => revision}
+      LinkProps={{
+        "aria-label": `External Git Link, project ${project.name}, revision ${gitRef}`
+      }}
+    />
+  );
+};
diff --git a/src/components/Job/JobTable/JobStatusColumn.js b/src/components/Job/JobTable/JobStatusColumn.js
new file mode 100644
index 0000000000000000000000000000000000000000..a82aa04e2727efb25f01dc3ee033f26950d9671c
--- /dev/null
+++ b/src/components/Job/JobTable/JobStatusColumn.js
@@ -0,0 +1,68 @@
+import React from "react";
+import EventIcon from "@mui/icons-material/Event";
+import AccessTimeIcon from "@mui/icons-material/AccessTime";
+import { Stack, Tooltip } from "@mui/material";
+import { formatDate, timeAgo } from "../../common/Helper";
+import LabeledIcon from "../../common/LabeledIcon";
+import moment from "moment";
+import { JobStatusIcon } from "../JobStatus";
+
+const formattedDuration = ({ startDate, finishDate }) => {
+  if (startDate && finishDate) {
+    return moment
+      .utc(finishDate.getTime() - startDate.getTime())
+      .format("HH:mm:ss");
+  } else {
+    return null;
+  }
+};
+
+export const JobStatusColumn = ({ job }) => {
+  const createOrStartDate = new Date(job?.startTime ?? job.createdAt);
+  const formattedCreateOrStartDate = `${
+    job?.startTime ? "Started" : "Created"
+  } ${timeAgo.format(new Date(createOrStartDate))}`;
+
+  const duration = formattedDuration({
+    finishDate: new Date(job.finishedAt),
+    startDate: new Date(createOrStartDate)
+  });
+
+  return (
+    <Stack>
+      <Stack gap={0.5}>
+        <JobStatusIcon job={job} />
+        <Stack>
+          <Tooltip
+            title={`${formatDate(createOrStartDate)}`}
+            aria-label={`${formattedCreateOrStartDate}, on ${formatDate(
+              createOrStartDate
+            )}`}
+          >
+            <LabeledIcon
+              label={formattedCreateOrStartDate}
+              LabelProps={{ variant: "body2" }}
+              labelPosition="right"
+              Icon={EventIcon}
+              IconProps={{ fontSize: "small" }}
+            />
+          </Tooltip>
+          {job?.finishedAt ? (
+            <Tooltip
+              title={`Finished ${job.finishedAt}`}
+              aria-label={`Finshed ${job.finishedAt}, after ${duration}`}
+            >
+              <LabeledIcon
+                label={`${duration}`}
+                LabelProps={{ variant: "body2" }}
+                labelPosition="right"
+                Icon={AccessTimeIcon}
+                IconProps={{ fontSize: "small" }}
+              />
+            </Tooltip>
+          ) : null}
+        </Stack>
+      </Stack>
+    </Stack>
+  );
+};
diff --git a/src/components/Job/JobTable/JobSummary.js b/src/components/Job/JobTable/JobSummary.js
new file mode 100644
index 0000000000000000000000000000000000000000..3383abea67e7c0bee7bf121fbfa93a3d5aaeca70
--- /dev/null
+++ b/src/components/Job/JobTable/JobSummary.js
@@ -0,0 +1,40 @@
+import { Chip, Link, Stack } from "@mui/material";
+import React from "react";
+import CommitIcon from "@mui/icons-material/Commit";
+import { JobGitRefLink } from "./JobGitRefLink";
+import { JobTypeIcon } from "../JobIcons";
+
+export const JobSummary = ({ job, colorStyle }) => {
+  return (
+    <Stack>
+      <JobTypeIcon
+        type={job.type}
+        colorStyle={colorStyle}
+        labelPosition="right"
+      />
+      <Link
+        href={`/iocs/${job.iocId}`}
+        aria-label={`IOC ${job.iocName}`}
+      >
+        {job.iocName}
+      </Link>
+      <Stack
+        flexDirection="row"
+        gap={0.5}
+        alignItems="center"
+      >
+        <Link
+          href={`/jobs/${job?.id}`}
+          aria-label={`Job ID ${job.id}`}
+        >{`#${job.id}`}</Link>
+        {job.type === "DEPLOY" ? (
+          <Chip
+            size="small"
+            icon={<CommitIcon />}
+            label={<JobGitRefLink job={job} />}
+          />
+        ) : null}
+      </Stack>
+    </Stack>
+  );
+};
diff --git a/src/components/Job/JobTable/JobTable.js b/src/components/Job/JobTable/JobTable.js
new file mode 100644
index 0000000000000000000000000000000000000000..13e3dfdedd1cfda970078d5f01c0947d6cb77b0f
--- /dev/null
+++ b/src/components/Job/JobTable/JobTable.js
@@ -0,0 +1,78 @@
+import React from "react";
+import { Table } from "@ess-ics/ce-ui-common";
+import { JobStatusColumn } from "./JobStatusColumn";
+import { JobSummary } from "./JobSummary";
+import { UserAvatar } from "../../common/User/UserAvatar";
+import { Link } from "@mui/material";
+
+const jobLogColumns = [
+  {
+    field: "status",
+    headerName: "Status"
+  },
+  {
+    field: "job",
+    headerName: "Job"
+  },
+  {
+    field: "host",
+    headerName: "Host"
+  },
+  {
+    field: "user",
+    headerName: "User",
+    align: "center",
+    headerAlign: "center"
+  }
+];
+
+const userPageJobLogColumns = [
+  ...jobLogColumns.filter((it) => it.field !== "user")
+];
+
+function createTableRow(job, colorStyle) {
+  return {
+    id: job.id,
+    status: <JobStatusColumn {...{ job }} />,
+    job: <JobSummary {...{ job, colorStyle }} />,
+    host: job.host?.hostName ? (
+      <Link
+        href={`/hosts/${job?.host?.externalHostId}`}
+        aria-label={`Host ${job.host?.hostName}`}
+      >
+        {job.host?.hostName}
+      </Link>
+    ) : null,
+    user: <UserAvatar username={job.createdBy} />
+  };
+}
+
+function createTableRowJobLog(job) {
+  return createTableRow(job, "black");
+}
+
+export function JobTable({
+  jobs,
+  rowType = "jobLog",
+  pagination,
+  onPage,
+  loading
+}) {
+  const tableTypeSpecifics = {
+    jobLog: [jobLogColumns, createTableRowJobLog],
+    userPageJobLog: [userPageJobLogColumns, createTableRowJobLog]
+  };
+
+  const [columns, createRow] = tableTypeSpecifics[rowType];
+
+  return (
+    <Table
+      columns={columns}
+      rows={jobs?.map((job) => createRow(job))}
+      pagination={pagination}
+      onPage={onPage}
+      loading={loading}
+      rowHeight={90}
+    />
+  );
+}
diff --git a/src/components/Job/JobTable/index.js b/src/components/Job/JobTable/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..539901071250e3d21ff44159d7dd070a7e96ca0e
--- /dev/null
+++ b/src/components/Job/JobTable/index.js
@@ -0,0 +1,4 @@
+import { JobTable } from "./JobTable";
+
+export { JobTable };
+export default JobTable;
diff --git a/src/components/common/Helper.js b/src/components/common/Helper.js
index d71c31046bc5c2a3b1172e4f113b488d4b043502..0983f74111e37844d4da510bb4ba91b5260007f6 100644
--- a/src/components/common/Helper.js
+++ b/src/components/common/Helper.js
@@ -2,6 +2,8 @@ import React, { useState, useEffect } from "react";
 import moment from "moment";
 import { alpha } from "@mui/material/styles";
 import { Link, Tooltip, Typography, styled } from "@mui/material";
+import TimeAgo from "javascript-time-ago";
+import en from "javascript-time-ago/locale/en";
 
 export function formatToList(items) {
   if (!items) return null;
@@ -205,3 +207,6 @@ export function pick(obj, keys) {
   }
   return ret;
 }
+
+TimeAgo.addDefaultLocale(en);
+export const timeAgo = new TimeAgo("en-GB");
diff --git a/src/components/common/LabeledIcon/LabeledIcon.js b/src/components/common/LabeledIcon/LabeledIcon.js
new file mode 100644
index 0000000000000000000000000000000000000000..d6e83f470fb8e0ece061959b06bc8455526bbbee
--- /dev/null
+++ b/src/components/common/LabeledIcon/LabeledIcon.js
@@ -0,0 +1,76 @@
+import React from "react";
+import { node, oneOfType, string, oneOf, object } from "prop-types";
+import { Stack, Tooltip, Typography } from "@mui/material";
+
+/**
+ * Component that renders an icon with a label.
+ *
+ * @param {object} Icon icon reference (provided as e.g. TheIcon, not as JSX e.g. <TheIcon />)
+ * @param {object} IconProps additional props to pass to the Icon. Accessibility props are already provided.
+ * @param {string} label text or Component to render as the label for the icon
+ * @param {object} LabelProps additional props to provide to the label when rendered as a Typography component
+ * (not applicable when positioned as "tooltip" or "none").
+ * @param {string} labelPosition describes position of the label. "tooltip" provides the label as a tooltip,
+ * "left" and "right" positions the label to the left or right respectively, and "none" provides no visible label
+ * (but still includes a11y attributes so that it is visible to screen readers)
+ */
+const LabeledIcon = React.forwardRef((props, ref) => {
+  const {
+    className,
+    Icon,
+    IconProps,
+    label,
+    LabelProps,
+    labelPosition = "tooltip",
+    ...rest
+  } = props;
+
+  if (labelPosition === "tooltip") {
+    return (
+      <Tooltip
+        title={label}
+        className={className}
+      >
+        <Icon
+          title={label}
+          titleAccess={label}
+          {...IconProps}
+        />
+      </Tooltip>
+    );
+  }
+  if (labelPosition === "none") {
+    return (
+      <Icon
+        title={label}
+        titleAccess={label}
+        {...IconProps}
+      />
+    );
+  }
+
+  const renderedLabel = <Typography {...LabelProps}>{label}</Typography>;
+  return (
+    <Stack
+      flexDirection="row"
+      gap={0.5}
+      alignItems="center"
+      className={className}
+      ref={ref}
+      {...rest}
+    >
+      {labelPosition === "left" ? renderedLabel : null}
+      <Icon {...IconProps} />
+      {labelPosition === "right" ? renderedLabel : null}
+    </Stack>
+  );
+});
+LabeledIcon.propTypes = {
+  Icon: node,
+  IconProps: object,
+  label: oneOfType([string, node]),
+  LabelProps: object,
+  labelPosition: oneOf(["tooltip", "right", "left", "none"])
+};
+
+export default LabeledIcon;
diff --git a/src/components/common/LabeledIcon/index.js b/src/components/common/LabeledIcon/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..484513514a310d79980055d46a2b48dd6bc4d55e
--- /dev/null
+++ b/src/components/common/LabeledIcon/index.js
@@ -0,0 +1,4 @@
+import LabeledIcon from "./LabeledIcon";
+
+export { LabeledIcon };
+export default LabeledIcon;
diff --git a/src/components/common/User/UserAvatar.js b/src/components/common/User/UserAvatar.js
new file mode 100644
index 0000000000000000000000000000000000000000..05b94e06371f9d250c11e0ee93ee884da24d5809
--- /dev/null
+++ b/src/components/common/User/UserAvatar.js
@@ -0,0 +1,76 @@
+import { useAPIMethod } from "@ess-ics/ce-ui-common/dist/hooks/API";
+import { Avatar, Tooltip, styled } from "@mui/material";
+import React, { useContext, useEffect, useMemo } from "react";
+import { apiContext } from "../../../api/DeployApi";
+import { Link } from "react-router-dom";
+import { userContext } from "@ess-ics/ce-ui-common/dist/contexts/User";
+
+const unpacker = (data) => {
+  if (data) {
+    return data[0];
+  } else {
+    return null;
+  }
+};
+
+export const UserAvatar = styled(({ username, size = 48 }) => {
+  const { user: userChanged } = useContext(userContext);
+
+  const client = useContext(apiContext);
+
+  const params = useMemo(
+    () => ({
+      user_name: username
+    }),
+    [username]
+  );
+
+  const {
+    value: user,
+    wrapper: getUser,
+    loading,
+    error
+  } = useAPIMethod({
+    fcn: client.apis.Git.infoFromUserName,
+    params,
+    unpacker
+  });
+
+  useEffect(() => {
+    getUser();
+  }, [userChanged, getUser]);
+
+  const renderedAvatar = (() => {
+    if (error || loading || !user?.avatar) {
+      return (
+        <Avatar
+          sx={{ width: size, height: size }}
+          alt={username}
+          variant="circle"
+        >
+          {username.toUpperCase().slice(0, 2)}
+        </Avatar>
+      );
+    }
+    return (
+      <Avatar
+        sx={{ width: size, height: size }}
+        src={user?.avatar}
+        alt={username}
+        variant="circle"
+      />
+    );
+  })();
+
+  return (
+    <Tooltip title={username}>
+      <Link
+        to={`/user/${username}`}
+        style={{ textDecoration: "none" }}
+        aria-label={`User Profile ${username}`}
+      >
+        {renderedAvatar}
+      </Link>
+    </Tooltip>
+  );
+})({});
diff --git a/src/components/common/User/index.js b/src/components/common/User/index.js
index 44989ea76755d9b0c09beb68eba9323e55729505..416c1fc44ff1a708b7b8c28bf8597077ee8f2184 100644
--- a/src/components/common/User/index.js
+++ b/src/components/common/User/index.js
@@ -1,5 +1,6 @@
 import { UserIocList } from "./UserIOCList";
 import { UserOperationList } from "./UserOperationList";
 import { UserProfile } from "./UserProfile";
+import { UserAvatar } from "./UserAvatar";
 
-export { UserIocList, UserOperationList, UserProfile };
+export { UserIocList, UserOperationList, UserProfile, UserAvatar };
diff --git a/src/components/deployments/DeploymentIcons.js b/src/components/deployments/DeploymentIcons.js
index c591afcb1a31eaff243f048da27897dce4444486..b7794ff07b7bfdd892d79a119fa04c88752d509d 100644
--- a/src/components/deployments/DeploymentIcons.js
+++ b/src/components/deployments/DeploymentIcons.js
@@ -7,26 +7,26 @@ import {
   AddCircleOutline,
   RemoveCircleOutline
 } from "@mui/icons-material";
-import { Tooltip } from "@mui/material";
 import { theme } from "../../style/Theme";
+import { LabeledIcon } from "../common/LabeledIcon";
 
 export function DeploymentStatusIcon({ status }) {
   const deploymentStatusIcons = {
     successful: {
       title: "Successful",
-      icon: <CheckCircleOutline />
+      icon: CheckCircleOutline
     },
     failed: {
       title: "Failed",
-      icon: <ErrorOutline />
+      icon: ErrorOutline
     },
     running: {
       title: "Running",
-      icon: <RotateRightOutlined />
+      icon: RotateRightOutlined
     },
     queued: {
       title: "Queued",
-      icon: <QueueOutlined />
+      icon: QueueOutlined
     }
   };
 
@@ -43,37 +43,38 @@ export function DeploymentStatusIcon({ status }) {
   const statusIcon = deploymentStatusIcons[state].icon;
 
   return (
-    <Tooltip
-      title={iconTitle}
-      style={iconStyle}
-    >
-      {statusIcon}
-    </Tooltip>
+    <LabeledIcon
+      label={iconTitle}
+      labelPosition="tooltip"
+      Icon={statusIcon}
+      IconProps={{ style: iconStyle }}
+    />
   );
 }
 
-export function DeploymentTypeIcon({ type }) {
+export function DeploymentTypeIcon({ type, labelPosition = "tooltip" }) {
   const deploymentTypeIcons = {
     deploy: {
       title: "Deployment",
-      icon: <AddCircleOutline />
+      icon: AddCircleOutline
     },
     undeploy: {
       title: "Undeployment",
-      icon: <RemoveCircleOutline />
+      icon: RemoveCircleOutline
     }
   };
 
   const iconStyle = { fill: theme.palette.status.icons };
   const iconTitle = deploymentTypeIcons[type.toLowerCase()].title;
-  const statusIcon = deploymentTypeIcons[type.toLowerCase()].icon;
+  const StatusIcon = deploymentTypeIcons[type.toLowerCase()].icon;
 
   return (
-    <Tooltip
-      title={iconTitle}
-      style={iconStyle}
-    >
-      {statusIcon}
-    </Tooltip>
+    <LabeledIcon
+      label={iconTitle}
+      LabelProps={{ noWrap: true }}
+      labelPosition={labelPosition}
+      Icon={StatusIcon}
+      IconProps={{ style: { iconStyle } }}
+    />
   );
 }
diff --git a/src/components/host/HostIcons.js b/src/components/host/HostIcons.js
index 38721d10317ba7effae147572021412569f03006..c0b66b1cd45d0efb32a928ccb22d242d0e4c053e 100644
--- a/src/components/host/HostIcons.js
+++ b/src/components/host/HostIcons.js
@@ -1,5 +1,5 @@
 import React from "react";
-import { Tooltip, useTheme } from "@mui/material";
+import { useTheme } from "@mui/material";
 import {
   Brightness1,
   ErrorOutline,
@@ -7,6 +7,7 @@ import {
   StopCircle,
   HelpOutline
 } from "@mui/icons-material";
+import LabeledIcon from "../common/LabeledIcon";
 
 export function HostStatusIcon({ host }) {
   const theme = useTheme();
@@ -16,23 +17,23 @@ export function HostStatusIcon({ host }) {
   const iconConfig = {
     available: {
       title: "Active",
-      icon: <Brightness1 />
+      icon: Brightness1
     },
     alert: {
       title: "Alert",
-      icon: <Error />
+      icon: Error
     },
     inactive: {
       title: "Inactive",
-      icon: <StopCircle />
+      icon: StopCircle
     },
     "inactive alert": {
       title: "Alert",
-      icon: <ErrorOutline />
+      icon: ErrorOutline
     },
     null: {
       title: "Unknown",
-      icon: <HelpOutline />
+      icon: HelpOutline
     }
   };
 
@@ -77,11 +78,11 @@ export function HostStatusIcon({ host }) {
   const statusIcon = iconConfig[state].icon;
 
   return (
-    <Tooltip
-      title={iconTitle}
-      style={iconStyle}
-    >
-      {statusIcon}
-    </Tooltip>
+    <LabeledIcon
+      label={iconTitle}
+      labelPosition="tooltip"
+      Icon={statusIcon}
+      IconProps={{ style: iconStyle }}
+    />
   );
 }
diff --git a/src/components/host/HostTable.spec.js b/src/components/host/HostTable.spec.js
index 92e2e74317de4e2087063e391c6df3106d263a7a..6287fad1470bfd9e112428c600c8fea807a3f025 100644
--- a/src/components/host/HostTable.spec.js
+++ b/src/components/host/HostTable.spec.js
@@ -38,7 +38,7 @@ describe("HostTable", () => {
         .each(($el, index) => {
           if (index === 0) {
             const iconTitle = firstRowData[index];
-            cy.wrap($el).findByLabelText(iconTitle).should("exist");
+            cy.wrap($el).findByRole("img", { name: iconTitle });
           } else {
             cy.wrap($el)
               .find("p")
diff --git a/src/components/records/RecordIcons.js b/src/components/records/RecordIcons.js
index b6922f9f2452a2e06c8c2f18f663888a66608481..e9f81c9a52010f0a951ab8c0cebea0009854b0fb 100644
--- a/src/components/records/RecordIcons.js
+++ b/src/components/records/RecordIcons.js
@@ -1,5 +1,6 @@
 import React from "react";
-import { Tooltip, useTheme } from "@mui/material";
+import { useTheme } from "@mui/material";
+import LabeledIcon from "../common/LabeledIcon";
 import { Brightness1, StopCircle, HelpOutline } from "@mui/icons-material";
 
 export function RecordStatusIcon({ record }) {
@@ -10,15 +11,15 @@ export function RecordStatusIcon({ record }) {
   const iconConfig = {
     active: {
       title: "Active",
-      icon: <Brightness1 />
+      icon: Brightness1
     },
     inactive: {
       title: "Inactive",
-      icon: <StopCircle />
+      icon: StopCircle
     },
     null: {
       title: "Unknown",
-      icon: <HelpOutline />
+      icon: HelpOutline
     }
   };
 
@@ -28,11 +29,11 @@ export function RecordStatusIcon({ record }) {
   const statusIcon = iconConfig[state].icon;
 
   return (
-    <Tooltip
-      title={iconTitle}
-      style={iconStyle}
-    >
-      {statusIcon}
-    </Tooltip>
+    <LabeledIcon
+      label={iconTitle}
+      labelPosition="tooltip"
+      Icon={statusIcon}
+      IconProps={{ style: iconStyle }}
+    />
   );
 }
diff --git a/src/stories/components/common/LabeledIcon/LabeledIcon.stories.js b/src/stories/components/common/LabeledIcon/LabeledIcon.stories.js
new file mode 100644
index 0000000000000000000000000000000000000000..f4251be32e517cebef9adf29f19d32b6064a7c5d
--- /dev/null
+++ b/src/stories/components/common/LabeledIcon/LabeledIcon.stories.js
@@ -0,0 +1,33 @@
+import React from "react";
+import LabeledIcon from "../../../../components/common/LabeledIcon/LabeledIcon";
+import AccountCircleIcon from "@mui/icons-material/AccountCircle";
+import { RouterHarness } from "../../../../mocks/AppHarness";
+
+export default {
+  title: "common/LabeledIcon",
+  argTypes: {
+    labelPosition: {
+      options: ["none", "right", "left"],
+      control: { type: "radio" }
+    }
+  }
+};
+
+const Template = (args) => {
+  return (
+    <RouterHarness>
+      <LabeledIcon
+        Icon={AccountCircleIcon}
+        {...args}
+      />
+    </RouterHarness>
+  );
+};
+
+export const Default = (args) => <Template {...args} />;
+Default.args = {
+  label: "Account",
+  LabelProps: { fontWeight: "bold" },
+  labelPosition: "right",
+  IconProps: { color: "primary" }
+};
diff --git a/src/views/jobs/JobListView.js b/src/views/jobs/JobListView.js
index 0d6ade23e747eae1f53987dbfe66c48b37a0288a..f57109c9ea62d15efe61b136230e9f813541a42f 100644
--- a/src/views/jobs/JobListView.js
+++ b/src/views/jobs/JobListView.js
@@ -12,7 +12,7 @@ import {
   deserialize
 } from "../../components/common/URLState/URLState";
 import { usePagination } from "../../hooks/pagination";
-import { JobTable } from "../../components/Job";
+import { JobTable } from "../../components/Job/JobTable";
 import { apiContext } from "../../api/DeployApi";
 
 export function JobListView() {