Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions dashboard/src/components/shared/ExtensionCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,20 @@ const openWebui = () => {
<v-icon icon="mdi-arrow-up-bold" start></v-icon>
{{ extension.online_version }}
</v-chip>
<v-chip
v-else-if="extension?.version_source_ahead && extension?.online_version"
color="info"
label
size="small"
variant="outlined"
>
<v-icon icon="mdi-information-outline" start></v-icon>
{{
tm("card.status.localVersionAhead", {
version: extension.online_version,
})
}}
</v-chip>
<v-chip
v-for="tag in extension.tags"
:key="tag"
Expand Down
1 change: 1 addition & 0 deletions dashboard/src/i18n/locales/en-US/features/extension.json
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,7 @@
},
"status": {
"hasUpdate": "New version available",
"localVersionAhead": "Installed version is newer than the current source (source {version})",
"disabled": "This extension is disabled",
"handlersCount": " handlers",
"supportPlatform": "Supported Platform",
Expand Down
1 change: 1 addition & 0 deletions dashboard/src/i18n/locales/ru-RU/features/extension.json
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,7 @@
},
"status": {
"hasUpdate": "Доступно обновление",
"localVersionAhead": "Установленная версия новее текущего источника (источник {version})",
"disabled": "Плагин выключен",
"handlersCount": "действий",
"supportPlatform": "Платформы",
Expand Down
1 change: 1 addition & 0 deletions dashboard/src/i18n/locales/zh-CN/features/extension.json
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,7 @@
},
"status": {
"hasUpdate": "有新版本可用",
"localVersionAhead": "当前插件版本比当前插件源更新(源版本 {version})",
"disabled": "该插件已经被禁用",
"handlersCount": "个行为",
"supportPlatform": "支持平台",
Expand Down
79 changes: 77 additions & 2 deletions dashboard/src/views/extension/useExtensionPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -658,12 +658,20 @@ export const useExtensionPage = () => {

if (matchedPlugin) {
extension.online_version = matchedPlugin.version;
const onlineVersion = String(matchedPlugin.version || "").trim();
const versionComparison = comparePluginVersions(
extension.version,
onlineVersion,
);

extension.version_source_ahead =
typeof versionComparison === "number" && versionComparison > 0;
extension.has_update =
extension.version !== matchedPlugin.version &&
matchedPlugin.version !== tm("status.unknown");
typeof versionComparison === "number" && versionComparison < 0;
Comment thread
sourcery-ai[bot] marked this conversation as resolved.
} else {
extension.online_version = "";
extension.has_update = false;
extension.version_source_ahead = false;
}
});
};
Expand Down Expand Up @@ -1284,6 +1292,73 @@ export const useExtensionPage = () => {

const normalizeAstrBotVersionSpec = (value) => String(value || "").trim();

const parsePluginVersion = (value) => {
const version = String(value || "").trim().replace(/^v/i, "");
const match = version.match(
/^([0-9]+(?:\.[0-9]+)*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+(.+))?$/,
);
if (!match) return null;

return {
parts: match[1].split(".").map((part) => Number.parseInt(part, 10)),
prerelease: match[2]
? match[2].split(".").map((part) => {
if (/^\d+$/.test(part)) {
return Number.parseInt(part, 10);
}
return part;
})
: null,
};
};

const comparePluginVersions = (left, right) => {
Comment thread
sourcery-ai[bot] marked this conversation as resolved.
const leftVersion = parsePluginVersion(left);
const rightVersion = parsePluginVersion(right);
if (!rightVersion) return null;
if (!leftVersion) return -1;

const length = Math.max(leftVersion.parts.length, rightVersion.parts.length);
for (let i = 0; i < length; i += 1) {
const leftPart = leftVersion.parts[i] || 0;
const rightPart = rightVersion.parts[i] || 0;
if (leftPart > rightPart) return 1;
if (leftPart < rightPart) return -1;
}

if (leftVersion.prerelease === null && rightVersion.prerelease !== null) {
return 1;
}
if (leftVersion.prerelease !== null && rightVersion.prerelease === null) {
return -1;
}
if (leftVersion.prerelease === null && rightVersion.prerelease === null) {
return 0;
}

const prereleaseLength = Math.max(
leftVersion.prerelease.length,
rightVersion.prerelease.length,
);
for (let i = 0; i < prereleaseLength; i += 1) {
const leftPart = leftVersion.prerelease[i];
const rightPart = rightVersion.prerelease[i];

if (leftPart === undefined && rightPart !== undefined) return -1;
if (leftPart !== undefined && rightPart === undefined) return 1;
if (typeof leftPart === "number" && typeof rightPart === "string") {
return -1;
}
if (typeof leftPart === "string" && typeof rightPart === "number") {
return 1;
}
if (leftPart > rightPart) return 1;
if (leftPart < rightPart) return -1;
}

return 0;
};

const normalizeVersionParts = (value) => {
const version = String(value || "")
.trim()
Expand Down
Loading