diff --git a/invenio_jobs/assets/semantic-ui/js/invenio_jobs/administration/RunsSearchResultItemLayout.js b/invenio_jobs/assets/semantic-ui/js/invenio_jobs/administration/RunsSearchResultItemLayout.js
index fc1f976..f55c783 100644
--- a/invenio_jobs/assets/semantic-ui/js/invenio_jobs/administration/RunsSearchResultItemLayout.js
+++ b/invenio_jobs/assets/semantic-ui/js/invenio_jobs/administration/RunsSearchResultItemLayout.js
@@ -10,11 +10,12 @@ import { NotificationContext } from "@js/invenio_administration";
import { i18next } from "@translations/invenio_app_rdm/i18next";
import PropTypes from "prop-types";
import React, { Component } from "react";
-import { UserListItemCompact, toRelativeTime } from "react-invenio-forms";
+import { UserListItemCompact } from "react-invenio-forms";
import { withState } from "react-searchkit";
import { Table } from "semantic-ui-react";
import { StatusFormatter } from "./StatusFormatter";
import { StopButton } from "./StopButton";
+import { diffTimestamps } from "./utils/diffTimestamps";
class SearchResultItemComponent extends Component {
constructor(props) {
@@ -60,7 +61,19 @@ class SearchResultItemComponent extends Component {
>
{result.started_at === null
? `${i18next.t("Waiting")}...`
- : toRelativeTime(result.started_at, i18next.language)}
+ : [
+ result.finished_at === null
+ ? `${diffTimestamps(
+ new Date().toISOString(),
+ result.started_at,
+ i18next.language
+ )}...`
+ : diffTimestamps(
+ result.finished_at,
+ result.started_at,
+ i18next.language
+ ),
+ ]}
)}
- {status === "RUNNING" || status === "QUEUED" ? (
+ {status === "RUNNING" ? (
{
diff --git a/invenio_jobs/assets/semantic-ui/js/invenio_jobs/administration/utils/diffTimestamps.js b/invenio_jobs/assets/semantic-ui/js/invenio_jobs/administration/utils/diffTimestamps.js
new file mode 100644
index 0000000..6a061ac
--- /dev/null
+++ b/invenio_jobs/assets/semantic-ui/js/invenio_jobs/administration/utils/diffTimestamps.js
@@ -0,0 +1,59 @@
+// This file is part of React-Invenio-Forms
+// Copyright (C) 2024 CERN.
+//
+// React-Invenio-Forms is free software; you can redistribute it and/or modify it
+// under the terms of the MIT License; see LICENSE file for more details.
+
+import { DateTime } from "luxon";
+
+/**
+ * Create duration string for two given timestamps
+ *
+ * @param firstTimestamp string ISO timestamp
+ * @param secondTimestamp string ISO timestamp
+ * @returns {string} string representation of duration, i.e. 3 days
+ */
+export const diffTimestamps = (
+ firstTimestamp,
+ secondTimestamp,
+ language = "en"
+) => {
+ const first = DateTime.fromISO(firstTimestamp);
+ const second = DateTime.fromISO(secondTimestamp);
+ const duration = first.diff(second).reconfigure({ locale: language });
+ // If we used a newer version of luxon we could just do this:
+ // return duration.toHuman();
+
+ // instead return the largest unit and value (ignore everything smaller)
+ const rescale = duration.shiftTo(
+ "years",
+ "months",
+ "weeks",
+ "days",
+ "hours",
+ "minutes",
+ "seconds",
+ "milliseconds"
+ ); // in new luxon this is just duration.rescale()
+ const units = [
+ "years",
+ "months",
+ "weeks",
+ "days",
+ "hours",
+ "minutes",
+ "seconds",
+ "milliseconds",
+ ];
+
+ for (const unit of units) {
+ if (rescale[unit] && rescale[unit] > 0) {
+ if (rescale[unit] === 1) {
+ return rescale[unit] + " " + unit.slice(0, -1); // remove s
+ } else {
+ return rescale[unit] + " " + unit;
+ }
+ }
+ }
+ return "-"; // in case all components are zero
+};