diff --git a/docs/upgrade.md b/docs/upgrade.md
index 640fed3ae3..e7247676d1 100644
--- a/docs/upgrade.md
+++ b/docs/upgrade.md
@@ -88,11 +88,11 @@ process, for example:
dpkg -i matrix-synapse-py3_1.3.0+stretch1_amd64.deb
```
-Generally Synapse database schemas are compatible across multiple versions, once
-a version of Synapse is deployed you may not be able to rollback automatically.
+Generally Synapse database schemas are compatible across multiple versions, but once
+a version of Synapse is deployed you may not be able to roll back automatically.
The following table gives the version ranges and the earliest version they can
be rolled back to. E.g. Synapse versions v1.58.0 through v1.61.1 can be rolled
-back safely to v1.57.0, but starting with v1.62.0 it is only safe to rollback to
+back safely to v1.57.0, but starting with v1.62.0 it is only safe to roll back to
v1.61.0.
<!-- REPLACE_WITH_SCHEMA_VERSIONS -->
diff --git a/docs/usage/administration/useful_sql_for_admins.md b/docs/usage/administration/useful_sql_for_admins.md
index 9f2cc9b957..41755cd3b6 100644
--- a/docs/usage/administration/useful_sql_for_admins.md
+++ b/docs/usage/administration/useful_sql_for_admins.md
@@ -205,3 +205,12 @@ SELECT user_id, device_id, user_agent, TO_TIMESTAMP(last_seen / 1000) AS "last_s
FROM devices
WHERE last_seen < DATE_PART('epoch', NOW() - INTERVAL '3 month') * 1000;
```
+
+## Clear the cache of a remote user's device list
+
+Forces the resync of a remote user's device list - if you have somehow cached a bad state, and the remote server is
+will not send out a device list update.
+```sql
+INSERT INTO device_lists_remote_resync
+VALUES ('USER_ID', (EXTRACT(epoch FROM NOW()) * 1000)::BIGINT);
+```
diff --git a/docs/website_files/version-picker.js b/docs/website_files/version-picker.js
index b6f35f29c7..3174b5d0bc 100644
--- a/docs/website_files/version-picker.js
+++ b/docs/website_files/version-picker.js
@@ -100,10 +100,30 @@ function sortVersions(a, b) {
if (a === 'develop' || a === 'latest') return -1;
if (b === 'develop' || b === 'latest') return 1;
- const versionA = (a.match(/v\d+(\.\d+)+/) || [])[0];
- const versionB = (b.match(/v\d+(\.\d+)+/) || [])[0];
+ // If any of the versions do not confrom to a semantic version string, they
+ // will be sorted behind a valid version.
+ const versionA = (a.match(/v(\d+(\.\d+)+)/) || [])[1]?.split('.') ?? '';
+ const versionB = (b.match(/v(\d+(\.\d+)+)/) || [])[1]?.split('.') ?? '';
- return versionB.localeCompare(versionA);
+ for (let i = 0; i < Math.max(versionA.length, versionB.length); i++) {
+ if (versionB[i] === undefined) {
+ return -1;
+ }
+ if (versionA[i] === undefined) {
+ return 1;
+ }
+
+ const partA = parseInt(versionA[i], 10);
+ const partB = parseInt(versionB[i], 10);
+
+ if (partA > partB) {
+ return -1;
+ } else if (partB > partA) {
+ return 1;
+ }
+ }
+
+ return 0;
}
/**
|