Skip to content

Commit

Permalink
Update dependency view to include end-of-life information
Browse files Browse the repository at this point in the history
Dependencies are considered to be near the end of their life when there
is less than one year of support remaining.

In this case, the second capsule used to display the latest version of
the dependency has been expanded to provide a timescale for this
deadline in a relative format, with an icon as a secondary visual
indicator:
- `bxs-hourglass` is used when the end-of-life date is upcoming
- `bxs-hourglass-bottom` is used when the end-of-life date has passed.
  • Loading branch information
danlivings-dxw committed Sep 17, 2024
1 parent eff3d6f commit 5c47225
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 54 deletions.
38 changes: 26 additions & 12 deletions index.njk
Original file line number Diff line number Diff line change
Expand Up @@ -75,21 +75,35 @@
<li>
<div class="inline-block whitespace-nowrap text-[0px]">
<span>
<span class="font-mono text-sm bg-{{ dependency.color }}-200 rounded-l-full last:rounded-r-full py-1 px-2">{{ dependency.name }}</span>
{% if dependency.version %}
<span class="font-mono text-sm bg-{{ dependency.color }}-300 last:rounded-r-full py-1 px-2">v{{ dependency.version }}</span>
{% endif %}
{% if dependency.tag %}
<span class="font-mono text-sm bg-{{ dependency.color }}-400 text-white last:rounded-r-full py-1 px-2">{{ dependency.tag }}</span>
{% endif %}
<span class="font-mono text-sm bg-{{ dependency.color }}-200 rounded-l-full last:rounded-r-full py-1 px-2">{{ dependency.name }}</span>
{% if dependency.version %}
<span class="font-mono text-sm bg-{{ dependency.color }}-300 last:rounded-r-full py-1 px-2">v{{ dependency.version }}</span>
{% endif %}
{% if dependency.tag %}
<span class="font-mono text-sm bg-{{ dependency.color }}-400 text-white last:rounded-r-full py-1 px-2">{{ dependency.tag }}</span>
{% endif %}
</span>
{% if dependency.isOutdated %}
<span class="inline-block w-1"></span>
<span class="font-mono text-sm bg-{{ dependency.color }}-500 text-white rounded-full py-1 px-2">
<i class="align-[-1px] bx {{dependency.icon}}"></i>
v{{ dependency.latestVersion }}
<span>
{% if dependency.isOutdated %}
<span class="font-mono text-sm bg-{{ dependency.color }}-500 text-white first:rounded-l-full last:rounded-r-full py-1 px-2">
<i class="align-[-1px] bx {{dependency.icon}}"></i>
{{ dependency.changelog }}
v{{ dependency.latestVersion }}
</span>
{% endif %}
{% if dependency.isEndOfLifeSoon %}
<span class="font-mono text-sm bg-{{ dependency.color }}-600 text-white first:rounded-l-full last:rounded-r-full py-1 px-2">
<i class="align-[-1px] bx bxs-hourglass"></i>
<span class="font-sans">Support ends {{ dependency.endOfLifeRelative }}</span>
</span>
{% elif dependency.isOutOfSupport %}
<span class="font-mono text-sm bg-{{ dependency.color }}-600 text-white first:rounded-l-full last:rounded-r-full py-1 px-2">
<i class="align-[-1px] bx bxs-hourglass-bottom"></i>
<span class="font-sans">Support ended {{ dependency.endOfLifeRelative }}</span>
</span>
{% endif %}
</span>
{% endif%}
</div>
</li>
{% endfor %}
Expand Down
94 changes: 52 additions & 42 deletions utils/index.js
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand All @@ -35,54 +69,30 @@ 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,
version: dependency.version,
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
Expand Down

0 comments on commit 5c47225

Please sign in to comment.