diff --git a/index.njk b/index.njk
index d17c1c6..4f6c7a7 100644
--- a/index.njk
+++ b/index.njk
@@ -75,21 +75,35 @@
- {{ dependency.name }}
- {% if dependency.version %}
- v{{ dependency.version }}
- {% endif %}
- {% if dependency.tag %}
- {{ dependency.tag }}
- {% endif %}
+ {{ dependency.name }}
+ {% if dependency.version %}
+ v{{ dependency.version }}
+ {% endif %}
+ {% if dependency.tag %}
+ {{ dependency.tag }}
+ {% endif %}
- {% if dependency.isOutdated %}
-
-
- v{{ dependency.latestVersion }}
+
+ {% if dependency.isOutdated %}
+
+
+ {{ dependency.changelog }}
+ v{{ dependency.latestVersion }}
+
+ {% endif %}
+ {% if dependency.isEndOfLifeSoon %}
+
+
+ Support ends {{ dependency.endOfLifeRelative }}
+
+ {% elif dependency.isOutOfSupport %}
+
+
+ Support ended {{ dependency.endOfLifeRelative }}
+
+ {% endif %}
- {% endif%}
{% endfor %}
diff --git a/utils/index.js b/utils/index.js
index 9be6d4f..870aa8e 100644
--- a/utils/index.js
+++ b/utils/index.js
@@ -1,5 +1,6 @@
import { readFile } from "fs/promises";
-import { getDependencyState } from "./endOfLifeDateApi/index.js";
+import { differenceInYears, formatDistance, startOfToday } from "date-fns";
+import { getDependencyEndOfLifeDate, getDependencyState } from "./endOfLifeDateApi/index.js";
/**
* @typedef {Object} PersistedData
@@ -15,14 +16,47 @@ import { getDependencyState } from "./endOfLifeDateApi/index.js";
* @property {string} org - The name of the Github organisation the repos belong to.
*/
+/**
+ * @typedef {"sky"|"amber"|"orange"|"red"} TailwindColor
+ */
+
+/**
+ * @typedef {"bx-check-circle"|"bx-up-arrow-circle"|"bxs-up-arrow-circle"|"bxs-x-circle"} Boxicon
+ */
+
/**
* @typedef {Object} UiDependency
* @property {string} name
* @property {string?} version
* @property {string?} tag
- * @property {string} color
+ * @property {TailwindColor} color
+ * @property {Boxicon} icon
+ * @property {string?} latestVersion
+ * @property {Date?} endOfLifeDate
+ * @property {string?} endOfLifeRelative
+ * @property {boolean} isOutdated
+ * @property {boolean} isOutOfSupport
+ * @property {boolean} isEndOfLifeSoon
*/
+const stateColors = {
+ "upToDate": "sky",
+ "minorUpdateAvailable": "amber",
+ "majorUpdateAvailable": "orange",
+ "endOfLife": "red",
+};
+
+const defaultColor = "stone";
+
+const stateIcons = {
+ "upToDate": "bx-check-circle",
+ "minorUpdateAvailable": "bx-up-arrow-circle",
+ "majorUpdateAvailable": "bxs-up-arrow-circle",
+ "endOfLife": "bxs-x-circle",
+};
+
+const defaultIcon = "bx-question-mark";
+
/**
* Maps the persisted dependency data from storage to a format suitable for the UI
* @param {import("../model/Dependency").Dependency} dependency
@@ -35,43 +69,15 @@ export const mapDependencyFromStorageToUi = (dependency, persistedLifetimes) =>
const state = lifetimes === undefined ? "unknown" : getDependencyState(dependency, lifetimes.lifetimes);
const latestVersion = lifetimes?.lifetimes[0]?.latest;
- let color;
- switch (state) {
- case "unknown":
- color = "stone";
- break;
- case "upToDate":
- color = "sky";
- break;
- case "minorUpdateAvailable":
- color = "amber";
- break;
- case "majorUpdateAvailable":
- color = "orange";
- break;
- case "endOfLife":
- color = "red";
- break;
- }
-
- let icon;
- switch (state) {
- case "unknown":
- icon = "bx-question-mark";
- break;
- case "upToDate":
- icon = "bx-check-circle";
- break;
- case "minorUpdateAvailable":
- icon = "bx-up-arrow-circle";
- break;
- case "majorUpdateAvailable":
- icon = "bxs-up-arrow-circle";
- break;
- case "endOfLife":
- icon = "bxs-x-circle";
- break;
- }
+ const color = stateColors[state] ?? defaultColor;
+ const icon = stateIcons[state] ?? defaultIcon;
+
+ const endOfLifeDate = lifetimes && getDependencyEndOfLifeDate(dependency, lifetimes.lifetimes);
+ const endOfLifeRelative = endOfLifeDate && formatDistance(endOfLifeDate, startOfToday(), { addSuffix: true });
+
+ const isOutdated = state !== "upToDate" && state !== "unknown";
+ const isOutOfSupport = state === "endOfLife";
+ const isEndOfLifeSoon = !!endOfLifeDate && !isOutOfSupport && differenceInYears(endOfLifeDate, startOfToday()) < 1;
return {
name: dependency.name,
@@ -79,10 +85,14 @@ export const mapDependencyFromStorageToUi = (dependency, persistedLifetimes) =>
tag: dependency.tag,
color,
icon,
- isOutdated: state !== "upToDate" && state !== "unknown",
latestVersion,
- }
-}
+ endOfLifeDate,
+ endOfLifeRelative,
+ isOutdated,
+ isOutOfSupport,
+ isEndOfLifeSoon,
+ };
+};
/**
* Maps the persisted repo data from storage to a format suitable for the UI