Skip to content
Merged
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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"url": "git+https://github.com/opencor/webapp.git"
},
"type": "module",
"version": "1.20261031.0",
"version": "1.20261102.0",
"engines": {
"bun": ">=1.2.0"
},
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
},
"./style.css": "./dist/opencor.css"
},
"version": "1.20261031.0",
"version": "1.20261102.0",
"libopencorVersion": "1.20261029.0",
"scripts": {
"build": "vite build && bun scripts/generate.version.ts",
Expand Down
38 changes: 32 additions & 6 deletions src/renderer/src/common/changelog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,29 +127,55 @@ const changelog = (): IOpenCORChangelogEntry[] => {
// scripts/generate.version.ts), i.e. the changelog of the latest deployed version (which may be even newer
// than the given version) with cache busting (i.e. by adding a timestamp query parameter to the URL so that
// the browser doesn't serve a cached version).
// Note #2: we don't want to bother the user if we cannot fetch the changes, so we just return an empty list in that
// case.
// Note #2: we return null if we cannot fetch the changes (within a given amount of time), so that our update available
// dialog can let the user know about it.
// Note #3: we keep track of the changes that we have fetched (or are fetching) for a given version, so that OpenCOR's
// Web app can fetch them as soon as it knows about a newer version (see OpenCOR.vue) and our update available
// dialog can then list them straightaway. We don't keep track of the changes that we failed to fetch, so that
// we can try again later.

const fetchChangelog = async (toVersion: string): Promise<IOpenCORChangelogEntry[]> => {
const CHANGELOG_FETCH_TIMEOUT = 3 * 1000; // 3 seconds.

const fetchedChangelogs = new Map<string, Promise<IOpenCORChangelogEntry[] | null>>();

const doFetchChangelog = async (toVersion: string): Promise<IOpenCORChangelogEntry[] | null> => {
const url = electronApi
? `https://raw.githubusercontent.com/opencor/webapp/v${toVersion}/src/renderer/changelog.json`
: `./assets/changelog.json?t=${Date.now()}`;

try {
const response = await fetch(url);
const response = await fetch(url, { signal: AbortSignal.timeout(CHANGELOG_FETCH_TIMEOUT) });

if (!response.ok) {
console.warn(`OpenCOR: failed to fetch the changelog (${response.status}: ${response.statusText}).`);

return [];
return null;
}

return changelogEntries(sanitisedChangelog(await response.json()), currentVersion, toVersion);
} catch (error: unknown) {
console.warn('OpenCOR: failed to fetch the changelog:', formatError(error));

return [];
return null;
}
};

const fetchChangelog = (toVersion: string): Promise<IOpenCORChangelogEntry[] | null> => {
let res = fetchedChangelogs.get(toVersion);

if (!res) {
res = doFetchChangelog(toVersion).then((entries: IOpenCORChangelogEntry[] | null) => {
if (entries === null) {
fetchedChangelogs.delete(toVersion);
}

return entries;
});

fetchedChangelogs.set(toVersion, res);
}

return res;
};

// Export our changelog functions.
Expand Down
11 changes: 11 additions & 0 deletions src/renderer/src/components/OpenCOR.vue
Original file line number Diff line number Diff line change
Expand Up @@ -845,6 +845,17 @@ const onSettingsMenu = (): void => {
};

// Update available dialog (for OpenCOR's Web app).
// Note: we fetch the changes for a newer version as soon as we know about it, so that our update available dialog can
// list them straightaway (see fetchChangelog() in changelog.ts).

vue.watch(
[version.updateAvailable, version.latestVersion],
([newUpdateAvailable, newLatestVersion]: [boolean, string]) => {
if (newUpdateAvailable) {
void changelog.fetchChangelog(newLatestVersion);
}
}
);

const onUpdateAvailable = () => {
updateVersion.value = version.latestVersion.value;
Expand Down
26 changes: 19 additions & 7 deletions src/renderer/src/components/dialogs/UpdateAvailableDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,14 @@
<div class="text-center">
<div class="text-3xl font-bold">OpenCOR <span class="highlight highlight-version">{{ version }}</span> is available!</div>
</div>
<div v-if="entries.length" class="space-y-2">
<div v-if="fetching || entries === null || entries.length" class="space-y-2">
<div class="text-lg font-bold">What's new:</div>
<ChangelogComponent class="max-h-64 overflow-y-auto" :entries="entries" />
<div v-if="fetching" class="flex items-center gap-2 text-muted-color">
<i class="pi pi-cog pi-spin" />
<span>Retrieving the changes...</span>
</div>
<div v-else-if="entries === null" class="text-muted-color">The changes could not be retrieved.</div>
<ChangelogComponent v-else class="max-h-64 overflow-y-auto" :entries="entries" />
</div>
<div class="space-y-2">
<div v-if="electronApi" class="text-center">
Expand Down Expand Up @@ -54,22 +59,29 @@ defineEmits<{
}>();

// Retrieve what is new between our current version (excluded) and the available version (included).
// Note: our dialog may get closed and shown again (possibly for another version) before the changes that we were
// fetching have been retrieved, in which case we ignore those changes since they may not be for the version that
// is now available.
// Note #1: OpenCOR shows our dialog as soon as it knows about a newer version, so we list the changes as soon as they
// have been fetched. OpenCOR's Web app, on the other hand, fetches them as soon as it knows about a newer
// version (see OpenCOR.vue), so they are normally already fetched by the time our dialog is shown, in which
// case we list them straightaway.
// Note #2: our dialog may get closed and shown again (possibly for another version) before the changes that we were
// fetching have been retrieved, in which case we ignore those changes since they may not be for the version
// that is now available.

const entries = vue.ref<IOpenCORChangelogEntry[]>([]);
const entries = vue.ref<IOpenCORChangelogEntry[] | null>([]);
const fetching = vue.ref(false);

let fetchId = 0;

const onShow = (): void => {
const crtFetchId = ++fetchId;

entries.value = [];
fetching.value = true;

void fetchChangelog(props.version).then((changelogEntries: IOpenCORChangelogEntry[]) => {
void fetchChangelog(props.version).then((changelogEntries: IOpenCORChangelogEntry[] | null) => {
if (crtFetchId === fetchId) {
entries.value = changelogEntries;
fetching.value = false;
}
});
};
Expand Down
Loading