Files
pleno-vue/src/components/release/ReleaseFrontendVersionBadge.vue
T
Jeppe Bundgaard c437c89cfa Add release management enhancements, runtime-aware frontend updates, and extensive test coverage
- Implement release update detection, asset preloading, and frontend version management.
- Add unit and E2E tests for release update workflows, widget behavior, and failure scenarios.
- Introduce new services for handling release ping, error reporting, and update installation workflows.
- Extend i18n for release-related components and error report localization.
- Add `ReleaseFrontendVersionBadge.vue` and related styles to display frontend update statuses.
2026-05-27 13:23:22 +02:00

116 lines
3.4 KiB
Vue

<script setup>
import { computed } from "vue";
import { useI18n } from "vue-i18n";
import {
isSameReleaseCommit,
releaseUpdateState,
shortReleaseCommit,
} from "@/services/releaseUpdate.js";
import { releaseRuntimeState } from "@/services/releaseTimeline.js";
const { locale } = useI18n({ useScope: "global" });
const textValue = (value) => String(value ?? "").trim();
const githubAccess = (version) =>
version?.metadata?.github_access && typeof version.metadata.github_access === "object"
? version.metadata.github_access
: {};
const githubCommit = (version) => {
const access = githubAccess(version);
return version?.commit && typeof version.commit === "object"
? version.commit
: access.commit || access.latest_commit || null;
};
const versionTimestamp = (version) => {
const commit = githubCommit(version);
return (
textValue(version?.deployed_at) ||
textValue(version?.released_at) ||
textValue(version?.promoted_at) ||
textValue(version?.created_at) ||
textValue(version?.commit_authored_at) ||
textValue(commit?.authored_at) ||
textValue(githubAccess(version)?.commit_authored_at)
);
};
const formatReleaseTime = (value) => {
const timestamp = textValue(value);
if (!timestamp) {
return "";
}
const parsed = new Date(timestamp);
if (Number.isNaN(parsed.getTime())) {
return timestamp;
}
return new Intl.DateTimeFormat(locale.value || undefined, {
dateStyle: "medium",
timeStyle: "short",
}).format(parsed);
};
const currentText = computed(() => shortReleaseCommit(releaseUpdateState.currentCommit));
const latestText = computed(() => shortReleaseCommit(releaseUpdateState.latestCommit));
const currentReleaseTime = computed(() =>
formatReleaseTime(versionTimestamp(releaseRuntimeState.versions?.frontend || null))
);
const hasLatestUpdate = computed(
() =>
Boolean(releaseUpdateState.latestCommit) &&
!isSameReleaseCommit(releaseUpdateState.currentCommit, releaseUpdateState.latestCommit)
);
const title = computed(() => {
const releaseTime = currentReleaseTime.value;
if (!hasLatestUpdate.value) {
return releaseTime ? `Frontend ${currentText.value} released ${releaseTime}` : `Frontend ${currentText.value}`;
}
return releaseTime
? `Frontend ${currentText.value} released ${releaseTime} to ${latestText.value}`
: `Frontend ${currentText.value} to ${latestText.value}`;
});
</script>
<template>
<span
class="release-frontend-version-badge"
:class="{ 'release-frontend-version-badge--update': hasLatestUpdate }"
:title="title"
data-testid="release-frontend-version-badge"
>
<span class="release-frontend-version-badge__commit">{{ currentText }}</span>
<template v-if="hasLatestUpdate">
<span class="release-frontend-version-badge__arrow">-&gt;</span>
<span class="release-frontend-version-badge__commit">{{ latestText }}</span>
</template>
</span>
</template>
<style scoped>
.release-frontend-version-badge {
min-width: 0;
display: inline-flex;
align-items: center;
gap: 5px;
padding: 0;
border: 0;
background: transparent;
color: #64748b;
font-family: "SFMono-Regular", Consolas, "Liberation Mono", monospace;
font-size: 0.68rem;
font-weight: 700;
line-height: 1.2;
white-space: nowrap;
}
.release-frontend-version-badge__commit {
padding: 0;
color: #64748b;
}
.release-frontend-version-badge--update {
color: #64748b;
}
.release-frontend-version-badge__arrow {
color: #64748b;
}
</style>