Merge branch 'workerapi' into worker-loading

This commit is contained in:
yflory 2025-02-26 18:15:45 +01:00
commit 791e33ccf3
23 changed files with 130 additions and 65 deletions

View File

@ -3,14 +3,18 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
.dockerignore
.editorconfig
.git
.gitignore
.gitmodules
.github
.reuse
.stylelintrc.js
.eslint.config.js
docker-compose.yml
traefik2.yml
Dockerfile*
*.png
*.md
/onlyoffice-builds.git/
/www/common/onlyoffice/dist/
blob
@ -18,3 +22,4 @@ block
customize
data
datastore
docs

View File

@ -4,6 +4,71 @@ SPDX-FileCopyrightText: 2023 XWiki CryptPad Team <contact@cryptpad.org> and cont
SPDX-License-Identifier: AGPL-3.0-or-later
-->
# ❄️ Winter release (2024.12.0)
## Goals
This version delivers fixes and improvements across CryptPad. We are particularly happy to release a fix of our OnlyOffice integration that could address long-standing issues with documents becoming corrupted. If confirmed at scale, this fix could dramatically improve the use of OnlyOffice apps in CryptPad.
## Improvements
- OnlyOffice integration
- Fix bug resulting in corrupted documents [#1736](https://github.com/cryptpad/cryptpad/pull/1736)
- Drive
- Links included in Drive exports [#1695](https://github.com/cryptpad/cryptpad/pull/1695)
- Rich Text
- Formatted tables and strikethrough text in Pad .md exports [#1720](https://github.com/cryptpad/cryptpad/pull/1720)
- Forms
- Form password warning [#1690](https://github.com/cryptpad/cryptpad/pull/1690)
- Performance improvements (1/3) to example-advanced.nginx.conf [#1709](https://github.com/cryptpad/cryptpad/pull/1709)
- Enable toggle in and out of calendars on small screens [#1584](https://github.com/cryptpad/cryptpad/pull/1584)
## Fixes
- Accessibility
- Kanban Focus order fix [#1708](https://github.com/cryptpad/cryptpad/pull/1708)
- Change iframe title [#1706](https://github.com/cryptpad/cryptpad/pull/1706)
- Fix keyboard trap inside Form description [#1672](https://github.com/cryptpad/cryptpad/pull/1672)
- Disable arrow key navigation in the drive while modal is active [#1669](https://github.com/cryptpad/cryptpad/pull/1669)
- Simulate click action for keyboard users in Ctrl+E modal [#1726](https://github.com/cryptpad/cryptpad/pull/1726)
- Drive
- Prevent links in trash from disappearing after drive reload [#1697](https://github.com/cryptpad/cryptpad/pull/1697)
- Restore multiple files/directories [#1692](https://github.com/cryptpad/cryptpad/pull/1692)
- Stop selection of all other trashed files when restoring single file [#1681](https://github.com/cryptpad/cryptpad/pull/1681)
- Notifications
- Calendar reminders in notification panel [#1721](https://github.com/cryptpad/cryptpad/pull/1721)
- Add Notifications padding [#1688](https://github.com/cryptpad/cryptpad/pull/1688)
- Notification fixes [#1674](https://github.com/cryptpad/cryptpad/pull/1674)
- Forms
- Fix some form storage-related bugs [#1723](https://github.com/cryptpad/cryptpad/pull/1723)
- Fix spacing issues in Forms [#1682](https://github.com/cryptpad/cryptpad/pull/1682)
- Fix padding in form questions [#1670](https://github.com/cryptpad/cryptpad/pull/1670)
- Helpdesk
- Fix "Closed" support tickets remaining in Inbox [#1719](https://github.com/cryptpad/cryptpad/pull/1719)
- 'Request edit' button [#1680](https://github.com/cryptpad/cryptpad/pull/1680)
- Fix example-code-typo [#1703](https://github.com/cryptpad/cryptpad/pull/1703)
## Upgrade notes
If you are upgrading from a version older than `2024.9.1` please read the upgrade notes of all versions between yours and `2024.9.1` to avoid configuration issues.
To upgrade:
1. Stop your server
2. Get the latest code with git
```bash
git fetch origin --tags
git checkout 2024.12.0
npm ci
npm run install:components
```
3. Restart your server
4. Review your instance's checkup page to ensure that you are passing all tests
# Autumn release (2024.9.0)
## Goals

View File

@ -5,7 +5,7 @@
---
services:
cryptpad:
image: "cryptpad/cryptpad:version-2024.12.0"
image: "cryptpad/cryptpad:version-2025.3.0"
hostname: cryptpad
environment:

View File

@ -46,6 +46,8 @@ module.exports = [{
"www/common/worker.bundle.js",
"src/tweetnacl",
"_build",
"testapi.js",
"rollup.config.mjs",
],
}, ...compat.extends("eslint:recommended", "plugin:compat/recommended"), {
plugins: {

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "cryptpad",
"version": "2024.12.0",
"version": "2025.3.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "cryptpad",
"version": "2024.12.0",
"version": "2025.3.0",
"license": "AGPL-3.0+",
"dependencies": {
"@mcrowe/minibloom": "^0.2.0",

View File

@ -1,7 +1,7 @@
{
"name": "cryptpad",
"description": "a collaborative office suite that is end-to-end encrypted and open-source",
"version": "2024.12.0",
"version": "2025.3.0",
"license": "AGPL-3.0+",
"repository": {
"type": "git",

View File

@ -13,6 +13,18 @@
return Array.prototype.slice.call(A, start, end);
};
Util.u8ToBase64 = (u8, cb) => {
const reader = new FileReader();
reader.onload = () => {
let res = reader.result;
let trim = res.slice(res.indexOf(',') + 1);
cb(trim);
};
reader.readAsDataURL(new Blob([u8]));
};
Util.shuffleArray = function (a) {
for (var i = a.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
@ -374,7 +386,7 @@
let href = url.href + (ignoreCache ? '?'+(+new Date()) : '');
if (typeof(self) !== "undefined" && self.crypto) {
// Browser
fetch(url.href).then(res => {
fetch(href).then(res => {
if (!res.ok) {
throw new Error(`Fetch error: ${res.status}`);
}

View File

@ -3,14 +3,11 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
(() => {
const factory = (AppConfig = {}, Util, Hash,
Realtime, Messages = {}) => {
const factory = (Util, Hash, Realtime) => {
let window = globalThis;
var module = {};
module.setCustomize = (data) => {
Messages = data.Messages;
AppConfig = data.AppConfig;
module.setCustomize = (/*data*/) => {
};
var clone = function (o) {
@ -985,19 +982,15 @@ const factory = (AppConfig = {}, Util, Hash,
if (typeof(module) !== 'undefined' && module.exports) {
module.exports = factory(
undefined,
require('./common-util'),
require('./common-hash'),
require('./common-realtime'),
undefined
);
} else if ((typeof(define) !== 'undefined' && define !== null) && (define.amd !== null)) {
define([
'/customize/application_config.js',
'/common/common-util.js',
'/common/common-hash.js',
'/common/common-realtime.js',
'/customize/messages.js',
], factory);
} else {
// unsupported initialization

View File

@ -3,14 +3,13 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
(() => {
const factory = (AppConfig = {}, Util, Hash,
const factory = (Util, Hash,
Constants, UOSetter, Crypto, Messages = {}) => {
let window = globalThis;
var module = {};
module.setCustomize = (data) => {
Messages = data.Messages;
AppConfig = data.AppConfig;
UOSetter.setCustomize(data);
};
@ -972,7 +971,6 @@ const factory = (AppConfig = {}, Util, Hash,
if (typeof(module) !== 'undefined' && module.exports) {
module.exports = factory(
undefined,
require('./common-util'),
require('./common-hash'),
require('./common-constants'),
@ -982,7 +980,6 @@ if (typeof(module) !== 'undefined' && module.exports) {
);
} else if ((typeof(define) !== 'undefined' && define !== null) && (define.amd !== null)) {
define([
'/customize/application_config.js',
'/common/common-util.js',
'/common/common-hash.js',
'/common/common-constants.js',

View File

@ -680,7 +680,7 @@ const factory = (ApiConfig = {}, Sortify, UserObject, ProxyManager,
return metadata;
};
Store.onMaintenanceUpdate = function (uid) {
Store.onMaintenanceUpdate = function (/*uid*/) {
// use uid in /api/broadcast so that all connected users will use the same cached
// version on the server
let origin = ApiConfig.httpUnsafeOrigin;
@ -695,7 +695,7 @@ const factory = (ApiConfig = {}, Sortify, UserObject, ProxyManager,
});
});
};
Store.onSurveyUpdate = function (uid) {
Store.onSurveyUpdate = function (/*uid*/) {
// use uid in /api/broadcast so that all connected users will use the same cached
// version on the server
let origin = ApiConfig.httpUnsafeOrigin;

View File

@ -3,12 +3,11 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
(() => {
const factory = (AppConfig = {}, Feedback, Hash, Util,
const factory = (Feedback, Hash, Util,
Messaging, Crypt, Mailbox, Messages = {},
Realtime, nThen, Crypto) => {
const setCustomize = data => {
AppConfig = data.AppConfig;
Messages = data.Messages;
};
@ -510,7 +509,6 @@ const factory = (AppConfig = {}, Feedback, Hash, Util,
if (typeof(module) !== 'undefined' && module.exports) {
module.exports = factory(
undefined,
require('../../common/common-feedback'),
require('../../common/common-hash'),
require('../../common/common-util'),
@ -524,7 +522,6 @@ if (typeof(module) !== 'undefined' && module.exports) {
);
} else if ((typeof(define) !== 'undefined' && define !== null) && (define.amd !== null)) {
define([
'/customize/application_config.js',
'/common/common-feedback.js',
'/common/common-hash.js',
'/common/common-util.js',

View File

@ -2,8 +2,6 @@
//
// SPDX-License-Identifier: AGPL-3.0-or-later
/* global importScripts */
const Interface = require('./interface');
const Util = require('../../common/common-util');
let start = (setConfig) => {

View File

@ -2,8 +2,6 @@
//
// SPDX-License-Identifier: AGPL-3.0-or-later
/* global importScripts */
const Interface = require('./interface');
let start = (setConfig) => {
let ready = false;
@ -50,7 +48,7 @@ let start = (setConfig) => {
}
};
});
}
};
module.exports = { start };

View File

@ -4,11 +4,10 @@
(() => {
const factory = (Util, Hash, Constants, Realtime, Cache, Rec,
Messages = {}, nThen, Listmap, FP, Crypto, ChainPad) => {
nThen, Listmap, FP, Crypto, ChainPad) => {
var Calendar = {};
Calendar.setCustomize = data => {
Messages = data.Messages;
Calendar.setCustomize = (/*data*/) => {
};
var getStore = function (ctx, id) {
@ -1218,7 +1217,6 @@ if (typeof(module) !== 'undefined' && module.exports) {
require('../../common/common-realtime'),
require('../../common/cache-store'),
require('../../common/recurrence'),
undefined,
require('nthen'),
require('chainpad-listmap'),
require('../../../www/lib/datepicker/flatpickr'),
@ -1233,7 +1231,6 @@ if (typeof(module) !== 'undefined' && module.exports) {
'/common/common-realtime.js',
'/common/outer/cache-store.js',
'/calendar/recurrence.js',
'/customize/messages.js',
'/components/nthen/index.js',
'chainpad-listmap',
'/lib/datepicker/flatpickr.js',

View File

@ -386,7 +386,7 @@
let href = url.href + (ignoreCache ? '?'+(+new Date()) : '');
if (typeof(self) !== "undefined" && self.crypto) {
// Browser
fetch(url.href).then(res => {
fetch(href).then(res => {
if (!res.ok) {
throw new Error(`Fetch error: ${res.status}`);
}

View File

@ -34,8 +34,6 @@ define([
Additionally, there is some basic functionality for import/export.
*/
var urlArgs = Util.find(Config, ['requireConf', 'urlArgs']) || '';
var postMessage = function (/*cmd, data, cb*/) {
/*setTimeout(function () {
AStore.query(cmd, data, cb);
@ -2701,7 +2699,7 @@ define([
}).then(waitFor(store => {
postMsg = store?.postMsg;
msgEv = store?.msgEv;
}))
}));
}).nThen(function () {
Channel.create(msgEv, postMsg, function (chan) {
console.log('Outer ready');

View File

@ -33,10 +33,11 @@ const factory = function () {
let called = false;
let msgEv = mkEvent();
let todo = (resolve, reject) => {
let todo = (resolve/*, reject*/) => {
if (called) { return; }
called = true;
let worker, postMsg;
if (!noWorker && !noSharedWorker && typeof(SharedWorker) !== "undefined") {
worker = new SharedWorker('/common/worker.bundle.js?' + urlArgs);
worker.onerror = function (e) {
@ -66,7 +67,6 @@ const factory = function () {
return void resolve({postMsg, msgEv});
}
// eslint-disable-next-line no-constant-condition
if (!noWorker && typeof(Worker) !== "undefined") {
worker = new Worker('/common/worker.bundle.js?' + urlArgs);
worker.onerror = function (e) {
@ -85,7 +85,7 @@ const factory = function () {
// aren't available
//if (typeof(require) === "undefined") { return; }
require(['/common/worker.bundle.js'], function (Store) {
let store = Store?.store
let store = Store?.store;
if (!store) { return void console.error("No store"); }
store.onMessage(function (data) {
if (data === "STORE_READY") { return; }
@ -107,7 +107,7 @@ const factory = function () {
};
let todoNode = (resolve, reject) => {
const Store = require('./worker.bundle');
let store = Store?.store
let store = Store?.store;
if (!store) {
reject('NOSTORE');
return void console.error("No store");
@ -116,7 +116,7 @@ const factory = function () {
if (data === "STORE_READY") { return; }
msgEv.fire({data: data, origin: ''});
});
postMsg = function (d) {
let postMsg = function (d) {
setTimeout(function () {
store.query(d);
});
@ -144,7 +144,7 @@ const factory = function () {
}
if (typeof(Worker) !== "undefined") {
try {
worker = new Worker('/common/testworker.js?' + urlArgs);
let worker = new Worker('/common/testworker.js?' + urlArgs);
worker.onerror = function (errEv) {
errEv.preventDefault();
errEv.stopPropagation();

View File

@ -444,7 +444,7 @@
"support_formContentError": "Błąd: treść jest pusta",
"support_formTitleError": "Błąd: tytuł jest pusty",
"support_formButton": "Wyślij",
"support_formHint": "Użyj tego formularza, aby bezpiecznie skontaktować się z administratorami.<br>Proszę zauważyć, że niektóre kwestie/pytania mogą być już poruszone w <a>Podręczniku Użytkownika CryptPad</a>. Prosimy nie tworzyć nowego zgłoszenia, jeśli masz już otwarte zgłoszenie dotyczące tego samego problemu. Zamiast tego odpowiedz na oryginalną wiadomość, podając dodatkowe informacje.",
"support_formHint": "Użyj tego formularza, aby bezpiecznie skontaktować się z administratorami.<br>Zwróć uwagę, że niektóre kwestie/pytania mogą być już poruszone w <a>Podręczniku Użytkownika CryptPad</a>. Prosimy nie tworzyć nowego zgłoszenia, jeśli masz już otwarte zgłoszenie dotyczące tego samego problemu. Zamiast tego odpowiedz na oryginalną wiadomość, podając dodatkowe informacje.",
"support_formTitle": "Nowe Zgłoszenie",
"support_cat_new": "Nowe zgłoszenie",
"support_disabledHint": "Ta instancja CryptPad nie jest jeszcze skonfigurowana do korzystania z formularza pomocy technicznej.",
@ -1783,5 +1783,9 @@
"admin_onboardingOptionsHint": "Zaznacz właściwą opcję dla Twojej instancji.<br>To ustawienie może być później zmienione w panelu administratora.",
"team_autoTrim": "Zmniejszanie historii dysku zespołu... Proszę czekać.",
"admin_mfa_confirm_enable": "Czy na pewno chcesz włączyć uwierzytelnianie wieloetapowe?",
"admin_mfa_confirm_disable": "Czy na pewno chcesz wyłączyć uwierzytelnianie wieloetapowe?"
"admin_mfa_confirm_disable": "Czy na pewno chcesz wyłączyć uwierzytelnianie wieloetapowe?",
"form_passwordWarning": "Zwróć uwagę, że hasło do formularza można ustawić tylko teraz, podczas tworzenia go, i nie może być ono zmienione później.",
"fm_restoreMultipleDialog": "Czy na pewni chcesz przywrócić {0} plików i/lub folderów do ich poprzedniej lokalizacji?",
"calendar_show": "Pokaż kalendarze",
"calendar_hide": "Ukryj kalendarze"
}

View File

@ -1783,5 +1783,9 @@
"dph_tmp_pw": "此模板受新密码保护。从您的云盘打开它以输入新密码。",
"duplicate": "重复",
"admin_logoButton": "上传新的",
"install_notes": "<ul class=\"cp-notes-list\"><li>在此页面上创建您的第一个管理员账号。管理员管理实例设置,包括存储配额,并有权访问审核工具。</li><li>您的密码是加密此实例上所有文档和管理员权限的密钥。<span class=\"red\">如果您丢失了密码,我们将无法恢复您的数据。</span></li><li>如果您使用的是共享计算机,<span class=\"red\">请记住在使用完后登出</span>。只关闭浏览器窗口会暴露您的账号。</li></ul>"
"install_notes": "<ul class=\"cp-notes-list\"><li>在此页面上创建您的第一个管理员账号。管理员管理实例设置,包括存储配额,并有权访问审核工具。</li><li>您的密码是加密此实例上所有文档和管理员权限的密钥。<span class=\"red\">如果您丢失了密码,我们将无法恢复您的数据。</span></li><li>如果您使用的是共享计算机,<span class=\"red\">请记住在使用完后登出</span>。只关闭浏览器窗口会暴露您的账号。</li></ul>",
"fm_restoreMultipleDialog": "是否确定要将 {0} 个文件和/或文件夹还原到其以前的位置?",
"calendar_hide": "隐藏日历",
"form_passwordWarning": "请注意,表单密码只能在创建时设置,以后不能更改。",
"calendar_show": "显示日历"
}

View File

@ -3,14 +3,11 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
(() => {
const factory = (AppConfig = {}, Util, Hash,
Realtime, Messages = {}) => {
const factory = (Util, Hash, Realtime) => {
let window = globalThis;
var module = {};
module.setCustomize = (data) => {
Messages = data.Messages;
AppConfig = data.AppConfig;
module.setCustomize = (/*data*/) => {
};
var clone = function (o) {
@ -985,19 +982,15 @@ const factory = (AppConfig = {}, Util, Hash,
if (typeof(module) !== 'undefined' && module.exports) {
module.exports = factory(
undefined,
require('./common-util'),
require('./common-hash'),
require('./common-realtime'),
undefined
);
} else if ((typeof(define) !== 'undefined' && define !== null) && (define.amd !== null)) {
define([
'/customize/application_config.js',
'/common/common-util.js',
'/common/common-hash.js',
'/common/common-realtime.js',
'/customize/messages.js',
], factory);
} else {
// unsupported initialization

View File

@ -3,14 +3,13 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
(() => {
const factory = (AppConfig = {}, Util, Hash,
const factory = (Util, Hash,
Constants, UOSetter, Crypto, Messages = {}) => {
let window = globalThis;
var module = {};
module.setCustomize = (data) => {
Messages = data.Messages;
AppConfig = data.AppConfig;
UOSetter.setCustomize(data);
};
@ -972,7 +971,6 @@ const factory = (AppConfig = {}, Util, Hash,
if (typeof(module) !== 'undefined' && module.exports) {
module.exports = factory(
undefined,
require('./common-util'),
require('./common-hash'),
require('./common-constants'),
@ -982,7 +980,6 @@ if (typeof(module) !== 'undefined' && module.exports) {
);
} else if ((typeof(define) !== 'undefined' && define !== null) && (define.amd !== null)) {
define([
'/customize/application_config.js',
'/common/common-util.js',
'/common/common-hash.js',
'/common/common-constants.js',

View File

@ -78,6 +78,7 @@
justify-content: flex-start;
align-items: center;
background-color: @cp_notif-bg;
border-top: 1px solid @cp_notif-table-border;
&.no-notifications {
display: none;
padding: 1rem 1rem;
@ -95,12 +96,14 @@
background-color: @cp_notif-hover;
}
}
.cp-avatar-calendar {
font-size: 45px;
padding: 0 12px;
overflow: hidden;
}
&.cp-app-notification-archived {
background-color: @cp_notif-bg;
}
&:not(:first-child) {
border-top: 1px solid @cp_notif-table-border;
}
&.dismissed {
display: none;
}

View File

@ -87,6 +87,8 @@ define([
// if the type of notification correspond
if (filterTypes.indexOf(data.content.msg.type) !== -1) {
notifsData.push(data);
var icon = $(el).find(".cp-reminder");
$(icon).addClass('cp-avatar-calendar');
$(notifsList).prepend(el);
}
};
@ -143,7 +145,7 @@ define([
$(loadmore).click();
}
common.mailbox.subscribe(["notifications"], {
common.mailbox.subscribe(["notifications", "reminders"], {
onMessage: function (data, el) {
addNotification(data, el);
},