From f2c9066968efc595285a6d0fc91e13e4c05899ab Mon Sep 17 00:00:00 2001 From: Weblate Date: Mon, 23 Sep 2024 19:55:08 +0200 Subject: [PATCH 01/49] Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (1783 of 1783 strings) Co-authored-by: Subtext6676 Co-authored-by: Weblate Translate-URL: https://weblate.cryptpad.org/projects/cryptpad/app/zh_Hans/ Translation: CryptPad/App --- www/common/translations/messages.zh.json | 306 +++++++++++++++++++++-- 1 file changed, 288 insertions(+), 18 deletions(-) diff --git a/www/common/translations/messages.zh.json b/www/common/translations/messages.zh.json index caa522ab2..d3c10c419 100644 --- a/www/common/translations/messages.zh.json +++ b/www/common/translations/messages.zh.json @@ -16,7 +16,8 @@ "contacts": "联系人", "form": "表单", "presentation": "演示文档", - "doc": "文档" + "doc": "文档", + "diagram": "图表" }, "common_connectionLost": "伺服器連線中斷
現在是唯讀狀態,直到連線恢復正常。", "typeError": "此文档与所选应用进程不兼容", @@ -38,10 +39,10 @@ "upgrade": "昇級", "MB": "MB", "GB": "GB", - "KB": "KB", + "KB": "kB", "formattedMB": "{0} MB", "formattedGB": "{0} GB", - "formattedKB": "{0} KB", + "formattedKB": "{0} kB", "pinLimitReached": "你已達到儲存容量上限", "pinLimitReachedAlert": "您已达到存储空间上限。 新的文档不会存储在您的 CryptDrive 中。
您可以从 CryptDrive 中删除文档或订阅高级优惠以提高您的存储空间上限。", "pinLimitNotPinned": "已达到存储空间上限。
此文档未存储在您的 CryptDrive 中。", @@ -136,7 +137,7 @@ "fm_info_root": "在此建立任何巢狀目錄夾以便於整理分類你的檔案。", "fm_info_template": "这些文档存储为模板。 创建新文档时可以重复使用它们。", "fm_info_trash": "清空垃圾筒好讓 CryptDrive 多出一些空間", - "fm_info_anonymous": "您没有登录,所以您的文档将在 {0} 天后过期。清除浏览器历史记录可能会使它们消失。
注册(无需个人信息)或登录以无限期地把它们储存在您的云盘里。 了解更多关于注册帐户的信息。", + "fm_info_anonymous": "您尚未登录,因此您的文档将在 {0} 天后过期。清除浏览器历史记录可能会导致它们消失。
注册(无需提供个人信息)或登录即可将文档无限期地存储在您的云盘中。阅读有关注册账号的更多信息。", "fm_error_cantPin": "內部伺服器出錯,請重新載入本頁並再試一次。", "fc_newfolder": "新資料夾", "fc_rename": "重新命名", @@ -159,7 +160,7 @@ "login_password": "密碼", "login_confirm": "確認你的密碼", "login_hashing": "散列你的密碼中,這要花上一點時間", - "login_noSuchUser": "無效的用戶名或密碼,請再試一次或重新註冊", + "login_noSuchUser": "用户名或密码无效", "login_invalUser": "要求用戶名", "login_invalPass": "要求密碼", "login_unhandledError": "發生了未預期的錯誤 :(", @@ -374,7 +375,7 @@ "chainpadError": "更新内容时出现严重错误。 此页面处于只读模式,以确保您不会丢失您的工作。
点击 Esc 以继续查看此文档,或重新加载后再次尝试编辑。", "inactiveError": "由于缺少活动,此文档已被删除。 按 Esc 创建一个新文档。", "deletedError": "该文档已被删除,不再可用。", - "expiredError": "此文档已过期,不再可用。", + "expiredError": "此文档已达到销毁日期,不再可用。", "anonymousStoreDisabled": "此 CryptPad 实例的管理员已禁用访客存储服务。 请登录以访问您自己的 CryptDrive。", "padNotPinnedVariable": "此文档将在 {4} 天不活动后过期,请{0}登录{1}或{2}注册{3}以保留它。", "padNotPinned": "此文档将在 3 个月不活动后过期,请{0}登录{1}或{2}注册{3}以保留它。", @@ -443,7 +444,7 @@ "settings_autostoreNo": "手动(从不询问)", "settings_autostoreYes": "自动", "settings_autostoreHint": "自动您访问的所有文档都存储在您的 CryptDrive 中。
手动(总是询问) 如果您还没有存储文档,系统会询问您是否需要将它们存储在您的 CryptDrive 中。
手动(从不询问) 文档不会自动存储在您的 CryptDrive 中。 存储它们的选项将被隐藏。", - "settings_autostoreTitle": "CryptDrive 中的 Pad 存储", + "settings_autostoreTitle": "CryptDrive 中的文档存储", "settings_resetThumbnailsDone": "所有的缩略图都被删除了。", "settings_resetThumbnailsAction": "清除", "settings_resetThumbnailsDescription": "清除浏览器中存储的所有文档缩略图。", @@ -502,8 +503,8 @@ "admin_updateLimitTitle": "更新用户配额", "admin_updateLimitButton": "更新配额", "admin_updateLimitHint": "可以随时强制更新用户存储限制,但仅在发生错误时才需要", - "admin_registeredHint": "您实例中的已注册用户数", - "admin_registeredTitle": "已注册用户", + "admin_registeredHint": "实例上的活动云盘数量", + "admin_registeredTitle": "用户和团队云盘", "admin_activePadsHint": "当前正在被查看或编辑的文档数(不重复)", "admin_activePadsTitle": "活跃的文档", "admin_activeSessionsHint": "活跃的 WebSocket 连接数(和已连接的唯一 IP 地址)", @@ -657,7 +658,7 @@ "footer_donate": "捐献", "admin_flushCacheDone": "清除缓存成功", "admin_flushCacheButton": "清除缓存", - "admin_flushCacheHint": "当服务器更新以后要求客户端必须更新相应的资源", + "admin_flushCacheHint": "在自定义或配置更改后强制所有用户下载最新文件。避免重启服务器,但会让每位活动用户重置其连接,请谨慎使用。", "trimHistory_success": "历史记录已被删除", "trimHistory_error": "删除历史记录时出错", "trimHistory_getSizeError": "计算云盘历史记录大小时出错", @@ -670,7 +671,7 @@ "dontShowAgain": "不再显示", "safeLinks_error": "此链接是从浏览器的地址栏中复制的,不提供对文档的访问。 请使用 分享 菜单直接与联系人分享或复制链接。 了解更多有关安全链接功能的信息。", "settings_safeLinksCheckbox": "启用安全链接", - "settings_cat_security": "保密", + "settings_cat_security": "安全和隐私", "imprint": "法律声明", "oo_sheetMigration_anonymousEditor": "本文档需要升级。 在注册用户打开之前,访客无法进行编辑。", "oo_sheetMigration_complete": "可用更新版本,按 OK 重新加载。", @@ -699,7 +700,7 @@ "team_inviteFrom": "从:", "team_inviteLinkCopy": "创建链接", "team_inviteLinkErrorName": "请为您邀请的人添加姓名。 他们可以稍后更改。 ", - "team_inviteLinkWarning": "第一个访问此链接的人将能够加入该团队并查看其内容。 谨慎分享。", + "team_inviteLinkWarning": "访问此链接的人员将能够加入此团队并查看其内容。请谨慎分享。", "team_inviteLinkLoading": "生成您的链接", "team_inviteLinkNoteMsg": "此消息将在收件人决定是否加入此团队之前显示。", "share_contactPasswordAlert": "此项目受密码保护。 因为您与 CryptPad 联系人共享它,所以收件人不必输入密码。", @@ -760,7 +761,7 @@ "team_listTitle": "您的团队", "team_maxTeams": "每个用户帐户只能是 {0} 个团队的成员。", "team_infoContent": "每个团队都有自己的 CryptDrive、存储配额、聊天和成员列表。 团队所有者可以删除整个团队,管理员可以邀请或踢除成员,成员可以离开团队。", - "team_avatarHint": "500KB 最大尺寸(png、jpg、jpeg、gif)", + "team_avatarHint": "最大尺寸为 500 kB(png、jpg、jpeg、gif)", "team_avatarTitle": "团队头像", "team_nameHint": "设置团队的名称", "team_nameTitle": "团队名称", @@ -847,7 +848,7 @@ "password_info": "您尝试打开的文档不再存在或受新密码保护。 输入正确的密码以访问内容。", "creation_newPadModalDescription": "单击一个应用进程以创建一个新文档。 您也可以按 Tab 选择应用进程,然后按 Enter 确认。", "creation_passwordValue": "密码", - "creation_expiration": "到期时间", + "creation_expiration": "销毁日期", "creation_noOwner": "没有拥有者", "creation_owners": "拥有者", "creation_create": "新建", @@ -1022,7 +1023,7 @@ "admin_archiveNote": "笔记", "bounce_danger": "您单击的链接不会指向网页,而是指向一些可能是恶意的代码或数据。\n\n(“{0}”)\n\nCryptPad 出于安全原因阻止这些。 单击确定将关闭此选项卡。", "bounce_confirm": "您即将离开:{0}\n\n您确定要访问“{1}”吗?", - "form_answerChoice": "请选择您希望如何回答此表格:", + "form_answerChoice": "请选择您想如何回答此表单:", "form_exportSheet": "导出到工作表", "premiumAccess": "作为 {0} 的订阅者,您可以在此抢先体验应用进程中创建新文档。 请注意,它是实验性的,不应信任重要数据。", "earlyAccessBlocked": "此应用进程在此实例上尚不可用", @@ -1322,7 +1323,7 @@ "settings_cacheTitle": "缓存", "docs_link": "文档", "creation_helperText": "在文档中打开", - "creation_expiresIn": "过期日期在", + "creation_expiresIn": "销毁于", "register_warning_note": "由于 CryptPad 的加密特性,如果您忘记了用户名和/或密码,服务管理员将无法恢复数据。 请将它们保存在安全的地方。", "register_notes": "
  • 您的密码是加密所有文档的密钥。 如果您丢失了,我们将无法恢复您的数据。
  • 如果您使用的是共享计算机,请记住 完成后退出。 只有关闭浏览器窗口才会暴露您的帐户。
  • 要在不登录的情况下保留您创建和/或存储的文档,请勾选“从您的访客会话导入文档”。
", "register_notes_title": "重要笔记", @@ -1393,7 +1394,7 @@ "admin_defaultlimitTitle": "存储限制 (MB)", "admin_defaultlimitHint": "未应用自定义规则时 CryptDrives(用户和团队)的最大存储限制", "admin_registrationTitle": "关闭注册", - "admin_registrationHint": "不允许任何新用户注册", + "admin_registrationHint": "实例的访问者无法创建账号。管理员可以创建邀请。", "snapshots_cantMake": "无法创建快照。 您已断开连接。", "snapshots_notFound": "此快照不再存在,因为文档的历史记录已被删除。", "snapshot_error_exists": "已经有这个版本的快照", @@ -1513,5 +1514,274 @@ "admin_pinLogAvailable": "Pin 日志可用", "admin_pinLogArchived": "Pin 日志已存档", "admin_blockKey": "阻止公钥", - "admin_conflictExplanation": "本文件有两个版本。 恢复存档版本将覆盖实时版本。 存档实时版本将覆盖存档版本。 这两项一旦操作都无法撤消。" + "admin_conflictExplanation": "本文件有两个版本。 恢复存档版本将覆盖实时版本。 存档实时版本将覆盖存档版本。 这两项一旦操作都无法撤消。", + "settings_mfaHint": "使用您选择的身份验证应用提供的额外验证码保护您的账号", + "done": "完成", + "mfa_setup_button": "开始 2FA 设置", + "mfa_recovery_hint": "如果您无法访问身份验证应用,您的 CryptPad 账号可能会锁定。此恢复代码可禁用 2FA 并让您重新登录。", + "mfa_disable": "禁用 2FA", + "settings_otp_code": "验证码", + "settings_removeOwnedButton": "销毁所拥有的文档", + "recovery_header": "2FA 恢复", + "calendar_rec_custom": "自定义", + "calendar_str_filter_yearday": "年份天数:{0}", + "calendar_str_filter_weekno": "周数:{0}", + "calendar_str_filter_month": "月份:{0}", + "calendar_rec_txt": "重复间隔", + "form_answer_new": "再次提交", + "form_allowNotifications": "新回复通知", + "form_editable_off": "仅限一次", + "form_editable_on_del": "一次和编辑/删除", + "form_multiple": "多次", + "form_multiple_edit": "多次和编辑/删除", + "form_editable_str": "提交", + "team_linkUsesInfinite": "(无限制使用)", + "form_anonymized": "回复是匿名的", + "form_responseNotification": "表单的新回复:{0}", + "recovery_forgot_text": "请复制以下信息并通过电子邮件发送给您的实例管理员", + "recovery_mfa_error": "未知错误。请重新加载并重试。", + "recovery_mfa_disabled": "此账号已禁用多因素身份验证。", + "admin_totpEnabled": "已启用 2FA", + "admin_totpDisable": "禁用此账号的 2FA", + "admin_registrationSsoTitle": "关闭 SSO 注册", + "admin_invitationTitle": "邀请链接", + "admin_invitationCreate": "创建邀请链接", + "admin_invitationHint": "即使注册已关闭,每个邀请链接都会创建一个账号。用户名和电子邮件仅用于识别您的身份。CryptPad 不会通过电子邮件发送邀请链接(或其他任何内容),请复制链接并使用您选择的安全渠道发送。", + "admin_invitationLink": "邀请链接", + "admin_invitationCopy": "复制链接", + "admin_invitationAlias": "用户名", + "admin_invitationEmail": "用户电子邮件", + "admin_invitationDeleteConfirm": "是否确定要删除此邀请?", + "admin_usersAdd": "添加已知用户", + "admin_usersTitle": "用户目录", + "admin_storeInvitedLabel": "自动存储受邀用户", + "admin_storeSsoLabel": "自动存储 SSO 用户", + "admin_usersRemove": "移除", + "register_invalidToken": "邀请链接无效", + "admin_usersBlock": "用户的登录阻止 URL(可选)", + "form_deleteAll": "删除全部", + "goLeft": "向左", + "goRight": "向右", + "dph_pad_moderated": "审核团队删除了此文档", + "dph_pad_moderated_account": "此文档因属于已暂停的账号而被删除", + "recovery_mfa_description": "如果您无法访问双因素身份验证方法,则可以使用恢复代码禁用账号的 2FA。请先输入您的用户名和密码:", + "admin_diskUsageWarning": "请谨慎使用!根据实例上存储的数据大小,生成此报告可能会消耗服务器上所有可用的内存并导致崩溃。", + "calendar_rec_every_date": "每 {0}", + "calendar_rec_yearly_nth": "每 {2} 的 {0} {1}", + "calendar_rec_monthly_nth": "每月 {0} {1}", + "calendar_nth_last": "最后", + "calendar_nth_5": "第五", + "calendar_rec_warn_update": "已修改重复此事件的规则。将会取代未来的事件。", + "calendar_rec_warn_delall": "此事件将不再重复。将会保留 {0} 的第一个事件,将会移除所有其他事件。", + "calendar_removeNotification": "移除提醒", + "team_inviteRole": "初始角色", + "team_inviteUses": "此链接允许的使用次数(0 = 无限制)", + "form_exportJSON": "导出为 JSON", + "form_settingsButton": "表单设置", + "form_editable_on": "一次和编辑", + "form_showCondorcetMethod": "孔多塞方法", + "form_condorcetSchulze": "舒尔茨", + "continue": "继续", + "mfa_setup_label": "要启用 2FA,请先输入您的账号密码", + "mfa_revoke_label": "要禁用 2FA,请先输入您的账号密码", + "mfa_revoke_button": "确认禁用 2FA", + "mfa_status_on": "此账号的 2FA 已启用", + "settings_otp_invalid": "验证码无效", + "settings_removeOwnedHint": "将会永久销毁您是唯一所有者的全部文档", + "recovery_mfa_secret": "请输入您的恢复代码以禁用账号的 2FA:", + "admin_totpRecoveryTitle": "2FA 恢复", + "admin_totpDisableButton": "禁用", + "register_nameTooLong": "用户名必须少于 {0} 个字符", + "loading_recover": "无法获取代码?恢复您的账号", + "recovery_mfa_secret_ph": "恢复代码", + "login_notFilledUser": "请填写用户名", + "login_notFilledPass": "请填写密码", + "calendar_settings": "日历设置", + "date": "日期", + "context_menu": "文件夹操作", + "label_viewMode": "切换视图模式", + "team_nameTooLong": "团队名称太长(最多 50 个字符)", + "selectLanguage": "选择语言", + "dph_reason": "原因:{0}", + "dph_sf_destroyed": "所有者销毁了分享的文件夹 {0}", + "dph_sf_destroyed_team": "所有者销毁了团队云盘 {1} 中分享的文件夹 {0}", + "admin_archiveAccount": "存档此账号", + "admin_archiveAccountInfo": "包括其拥有的文件", + "admin_restoreAccount": "还原此账号", + "admin_accountSuspended": "管理员存档的账号", + "admin_accountReport": "账号存档报告", + "admin_accountReportFull": "获取详情报告", + "admin_channelPlaceholder": "已销毁的文档占位符", + "dph_default": "此内容不再可用", + "dph_account_destroyed": "所有者删除了此账号", + "dph_account_inactive": "此账号因未活动而被删除", + "dph_account_pw": "此账号的密码已更改", + "dph_pad_inactive": "此文档因未活动而被删除", + "dph_account_moderated": "审核团队暂停了此账号", + "dph_pad_pw": "此文档受新密码保护", + "dph_tmp_destroyed": "所有者销毁了此模板", + "dph_tmp_moderated": "审核团队删除了此模板", + "access_passwordUsed": "此密码已用于此文档。不可再次使用。", + "status": "状态页", + "calendar_rec_freq_weekly": "周", + "calendar_str_until": "直到 {0}", + "calendar_rec_freq_monthly": "月", + "calendar_str_for": "{0} 次", + "calendar_str_nthdayofmonth": "在 {1} 的 {0}", + "calendar_rec_freq_yearly": "年", + "calendar_str_monthday": "在 {0}", + "calendar_rec_until": "停止重复", + "calendar_rec_until_no": "从不", + "calendar_str_day": "在 {0}", + "calendar_rec_until_date": "在", + "calendar_str_daily": "{0} 天", + "calendar_rec_until_count": "之后", + "calendar_rec_until_count2": "时间", + "calendar_str_weekly": "{0} 周", + "calendar_rec_monthly_pick": "按天", + "calendar_str_monthly": "{0} 月", + "calendar_str_yearly": "{0} 年", + "calendar_nth_1": "第一", + "calendar_list_end": "{0} 或 {1}", + "calendar_nth_2": "第二", + "calendar_list": "{0}, {1}", + "calendar_nth_3": "第三", + "calendar_month_last": "最后一天", + "calendar_nth_4": "第四", + "form_condorcetRanked": "排列成双制", + "form_showDetails": "详情", + "form_noCondorcetWinner": "没有赢家", + "form_showCondorcetWinner": "赢家: ", + "form_type_date": "日期", + "mfa_revoke_code": "请输入您的验证码", + "mfa_recovery_warning": "将不再显示此代码,请立即将其保存在安全的地方,不要与任何人分享。", + "settings_removeOwnedText": "正在销毁您的文档,请稍候…", + "recovery_forgot": "忘记恢复代码", + "admin_totpFailed": "签名验证失败", + "calendar_desc": "描述", + "calendar_description": "描述:{0}{1}", + "sso_login_description": "登录方式", + "sso_register_description": "注册方式", + "ssoauth_header": "CryptPad 密码", + "ssoauth_form_hint_login": "请输入您的 CryptPad 密码", + "kanban_hideTags": "查看更少的标签", + "kanban_showTags": "查看全部标签", + "loading_mfa_required": "此实例需要双因素身份验证。请使用身份验证应用和下方表单更新您的账号。", + "team_autoTrim": "正在精简团队云盘历史…请稍候。", + "admin_mfa_confirm_enable": "是否确定要启用多因素身份验证?", + "admin_mfa_confirm_disable": "是否确定要禁用多因素身份验证?", + "admin_colorTitle": "强调色", + "admin_logoTitle": "自定义徽标", + "admin_logoHint": "SVG、PNG 或 JPG,最大尺寸为 200 kB", + "admin_logoRemoveButton": "还原默认", + "admin_colorHint": "更改您的 CryptPad 实例的强调色。请确保文本和按钮在浅色和深色主题下都清晰可辨且具有足够的对比度。", + "admin_colorCurrent": "当前强调色", + "admin_colorChange": "更改颜色", + "admin_colorPick": "选择颜色", + "admin_colorPreview": "预览颜色", + "admin_supportSetupHint": "创建或更新支持密钥。", + "admin_supportSetupTitle": "初始化支持", + "admin_supportEnabled": "已启用支持系统。", + "admin_supportDisabled": "已禁用支持系统。", + "admin_supportDelete": "禁用支持", + "admin_supportConfirm": "是否确定?这将删除所有现有的工单,并阻止所有审核员访问。", + "admin_supportMembers": "支持团队", + "support_cat_open": "收件箱", + "support_cat_search": "搜索", + "admin_supportAdd": "向支持团队添加联系人", + "support_cat_closed": "已关闭", + "support_cat_settings": "设置", + "support_openTicketTitle": "与用户打开工单", + "support_cat_legacy": "传统", + "support_pending": "存档的工单:", + "support_pending_tag": "已存档", + "support_active_tag": "收件箱", + "support_closed_tag": "已关闭", + "support_privacyTitle": "匿名回答", + "support_userChannel": "用户的通知渠道 ID", + "support_privacyHint": "选中此选项以“支持团队”而不是您自己的用户名进行回复", + "support_notificationsTitle": "禁用通知", + "support_notificationsHint": "选中此选项可禁用新工单和回复的通知", + "support_recordedId": "片段 ID(唯一)", + "support_userKey": "用户的公钥", + "support_invalChan": "通知渠道无效", + "admin_supportTeamTitle": "管理支持团队", + "admin_supportTeamHint": "在实例支持团队中添加和移除人员", + "support_pasteUserData": "在此处粘贴用户数据", + "support_legacyButton": "获取活动工单", + "support_recordedTitle": "片段", + "support_recordedHint": "将常用文本存储为单击快捷方式以插入支持消息中。", + "support_recordedContent": "内容", + "support_recordedEmpty": "没有片段", + "support_legacyTitle": "查看旧的支持数据", + "support_searchLabel": "搜索(标题或工单 ID)", + "support_legacyHint": "从旧支持系统中查看工单,并在新系统中重新创建。", + "support_legacyDump": "导出全部", + "support_legacyClear": "为此账号删除", + "support_team": "支持团队", + "support_answerAs": "作为 {0} 回答", + "support_movePending": "移动到存档", + "support_moveActive": "移动到活动", + "support_copyUserData": "复制用户数据", + "support_insertRecorded": "插入片段", + "admin_supportInit": "在此实例上初始化帮助台", + "moderationPage": "帮助台", + "admin_supportOpen": "打开帮助台", + "admin_cat_users": "用户目录", + "support_userNotification": "新的支持工单或回复:{0}", + "install_token": "安装令牌", + "install_header": "安装", + "admin_appSelection": "应用配置", + "install_instance": "创建第一个管理员账号,然后继续自定义此实例", + "install_launch": "实例设置", + "admin_appsTitle": "实例应用程序", + "admin_appsHint": "选择要在此实例上启用的应用。", + "admin_cat_apps": "应用程序", + "onboarding_save_error": "某些选项无法正确保存。请访问管理面板检查值。", + "onboarding_upload": "选择徽标", + "admin_onboardingNameTitle": "欢迎使用您的 CryptPad 实例", + "admin_onboardingNameHint": "请选择标题、描述、强调色和徽标(均为可选)", + "admin_onboardingOptionsTitle": "实例选项", + "admin_onboardingNamePlaceholder": "实例标题", + "admin_onboardingDescPlaceholder": "实例描述文本", + "settings_otp_tuto": "请使用您的身份验证应用扫描此二维码,并输入验证码进行确认。", + "admin_totpCheck": "签名验证成功", + "team_linkUses": "(剩余 {0}/{1})", + "calendar_str_filter_monthday": "月份天数:{0}", + "calendar_str_filter": "筛选器:", + "calendar_rec_freq_daily": "天", + "calendar_rec_warn_del": "此事件将不再重复。将会移除未来的事件。", + "form_alreadyAnsweredMult": "您在以下时间回复了此表单:", + "form_condorcetExtendedDisplay": "每位候选人赢得的比赛数量: ", + "mfa_recovery_title": "立即保存此恢复代码", + "admin_totpRecoveryMethod": "2FA 恢复方法", + "dph_tmp_moderated_account": "此模板因属于已暂停的账号而被删除", + "calendar_rec_change": "将重复事件移动到不同的日历。您只能将此更改应用于此事件或所有重复事件。", + "admin_forcemfaTitle": "强制性双因素身份验证", + "admin_usersHint": "此实例上的已知账号列表。选择以下选项可自动添加账号,或使用表单手动输入信息。", + "admin_usersRemoveConfirm": "是否确定要从目录中移除此用户?他们仍然可以访问和使用其账号。", + "support_openTicketHint": "从收件人用户的个人资料页面或现有的支持工单中复制收件人用户的数据。他们将收到有关此消息的 CryptPad 通知。", + "admin_onboardingOptionsHint": "请为您的实例选择合适的选项。
稍后可以在管理面板中更改这些设置。", + "calendar_rec_warn_updateall": "已修改重复此事件的规则。将会保留 {0} 的第一个事件,将会替换所有其他事件。", + "loading_enter_otp": "此账号受双因素身份验证保护。请输入您的验证码", + "dph_sf_pw": "分享的文件夹 {0} 受新密码保护。输入新密码即可访问或从云盘中移除此文件夹。", + "dph_pad_destroyed": "所有者销毁了此文档", + "settings_mfaTitle": "双因素身份验证(2FA)", + "mfa_status_off": "此账号的 2FA 未启用", + "mfa_enable": "启用 2FA", + "settings_removeOwnedTitle": "销毁所有拥有的文档", + "admin_totpRecoveryHint": "用户可以在 2FA 恢复页面 /recovery/ 复制恢复数据,然后将其通过电子邮件发送给实例管理员。粘贴以下恢复数据即可为账号禁用 2FA", + "label_logo": "CryptPad 徽标", + "team_nameAlreadySet": "团队名称已设置为 {0}", + "admin_archiveAccountConfirm": "请指定存档的原因,这将显示给用户。", + "calendar_rec_change_first": "将第一个重复事件移动到不同的日历。也将移动所有重复事件。", + "ssoauth_form_hint_register": "添加 CryptPad 密码以增强安全性,或留空并继续。如果不添加密码,实例管理员将可以使用保护数据的密钥。", + "admin_forcemfaHint": "将要求此实例上的全部用户设置双因素身份验证才能登录其账号。请注意,现有用户如果不设置 TOTP 应用程序将无法继续使用其账号。", + "admin_cat_security": "安全", + "admin_cat_customize": "自定义", + "admin_supportRotateNotify": "警告:已生成新密钥,但意外错误导致系统无法将其发送给审核员。请移除并重新添加支持团队的所有成员", + "dph_tmp_pw": "此模板受新密码保护。从您的云盘打开它以输入新密码。", + "duplicate": "重复", + "admin_logoButton": "上传新的", + "install_notes": "
  • 在此页面上创建您的第一个管理员账号。管理员管理实例设置,包括存储配额,并有权访问审核工具。
  • 您的密码是加密此实例上所有文档和管理员权限的密钥。如果您丢失了密码,我们将无法恢复您的数据。
  • 如果您使用的是共享计算机,请记住在使用完后登出。只关闭浏览器窗口会暴露您的账号。
" } From 02ccfd8444bc7ce2605bba6a848eb40cd6a23d6c Mon Sep 17 00:00:00 2001 From: Weblate Date: Mon, 23 Sep 2024 19:55:08 +0200 Subject: [PATCH 02/49] Translated using Weblate (Lithuanian) Currently translated at 10.3% (184 of 1783 strings) Co-authored-by: Vaclovas Intas Translate-URL: https://weblate.cryptpad.org/projects/cryptpad/app/lt/ Translation: CryptPad/App --- www/common/translations/messages.lt.json | 53 +++++++++++++----------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/www/common/translations/messages.lt.json b/www/common/translations/messages.lt.json index cfa36b872..62e36ce28 100644 --- a/www/common/translations/messages.lt.json +++ b/www/common/translations/messages.lt.json @@ -64,44 +64,47 @@ "synchronizing": "Sinchronizuojama", "disconnected": "Atjungta", "realtime_unrecoverableError": "Įvyko neatkuriama klaida. Norėdami perkrauti, spustelėkite Gerai.", - "disabledApp": "Ši programa buvo išjungta. Norėdami gauti daugiau informacijos, susisiekite su „CryptPad“ administratoriumi.", - "mustLogin": "Norėdami patekti į šį puslapį, turite būti prisijungę", - "deletedFromServer": "Dokumentas ištrintas", + "disabledApp": "Ši programa buvo išjungta. Susisiekite su šio „CryptPad“ administratoriumi, kad gautumėte daugiau informacijos.", + "mustLogin": "Turite būti prisijungę, kad pasiektumėte šį puslapį", + "deletedFromServer": "Dokumentas sunaikintas", "deleted": "Ištrinta", - "saved": "Užsaugota", + "saved": "Išsaugota", "error": "Klaida", - "loading": "Kraunasi...", - "newVersionError": "Yra nauja „CryptPad“ versija.
Perkraukite iš naujo , jei norite naudoti naują versiją, arba paspauskite „Esc“, kad pasiektumėte savo turinį offline režimu .", - "errorRedirectToHome": "Paspauskite Esc, kad būtumėte nukreipti į „CryptDrive“.", - "errorCopy": " Vis dar galite naudoti dabartinę versiją tik skaitymo režimu paspausdami Esc.", - "invalidHashError": "Prašytame dokumente yra neteisingas URL.", - "chainpadError": "Atnaujinant turinį įvyko kritinė klaida. Šis puslapis veikia tik skaitymo režimu, kad neprarastumėte savo darbo.
Jei norite toliau peržiūrėti šį padą, paspauskite Esc arba įkelkite iš naujo, jei norite bandyti redaguoti dar kartą.", - "inactiveError": "Šis padas buvo ištrintas dėl neveiklumo. Paspauskite Esc, kad sukurtumėte naują padą.", - "deletedError": "Šis dokumentas ištrintas ir jo nebėra.", - "expiredError": "Šis Padas nebegalioja ir yra ištrintas.", - "anonymousStoreDisabled": "Šios instancijos nepalaiko anoniminio vartojimo. Jūs turite prisiregistruoti, kad galėtumete naudoti CryptDrive.", - "padNotPinnedVariable": "Šis padas nustos galioti po {4} neaktyvių dienų, {0}prisijungti{1} arba {2}registruotis{3} kad užsaugoti.", - "padNotPinned": "Nenaudojamas padas nustos galioti po 3mėn, {0}prisijungti{1} arba {2} registruotis{3} kad užsaugoti.", - "onLogout": "Jūs esate prisijungęs, {0}Spausti čia{1}Prisjungti čia
arba spausti Esc pasiekti savo pad tik skaityti.", - "typeError": "Šis Pad nesuderinama su pasirinkta programa", - "common_connectionLost": " serverio sujungimas prarastas
Tik skaitymo rėžimas kol sujungimas atsiras.", + "loading": "Įkeliama...", + "newVersionError": "Yra nauja „CryptPad“ versija.
Perkraukite, kad naudotumėte naująją versiją, arba paspauskite Gr (Esc), kad pasiektumėte savo turinį neprisijungimo režimu.", + "errorRedirectToHome": "Paspauskite Gr (Esc), kad būtumėte nukreipti į „CryptDrive“.", + "errorCopy": " Dabartinę versiją vis dar galite naudoti tik skaitymo režimu, paspaudę Gr (Esc).", + "invalidHashError": "Jūsų prašomo dokumento turi netinkamą URL adresą.", + "chainpadError": "Įvyko kritinė klaida atnaujinant turinį. Šis puslapis yra tik skaitymo režime, kad neprarastumėte savo darbo.
Spustelėkite Gr (Esc), kad toliau peržiūrėtumėte šį dokumentą, arba perkraukite ir bandykite redaguoti dar kartą.", + "inactiveError": "Šis dokumentas buvo ištrintas dėl neaktyvumo. Paspauskite Gr (Esc), kad sukurtumėte naują dokumentą.", + "deletedError": "Šis dokumentas buvo ištrintas ir nebėra pasiekiamas.", + "expiredError": "Šis dokumentas pasiekė sunaikinimo datą ir nebėra pasiekiamas.", + "anonymousStoreDisabled": "Šio „CryptPad“ serverio administratorius išjungė saugyklą svečiams. Prisijunkite, kad pasiektumėte savo „CryptDrive“.", + "padNotPinnedVariable": "Šis dokumentas baigs galioti po {4} dienų neaktyvumo, {0}prisijunkite{1} arba {2}užsiregistruokite{3}, kad jį išsaugotumėte.", + "padNotPinned": "Šis dokumentas baigs galioti po 3 mėnesių neaktyvumo, {0}prisijunkite{1} arba {2}užsiregistruokite{3}, kad jį išsaugotumėte.", + "onLogout": "Esate atsijungę, {0}paspauskite čia{1}, kad prisijungtumėte
arba paspauskite Gr (Esc), kad prisijungtumėte prie dokumento tik skaitymo režimu.", + "typeError": "Šis dokumentas nesuderinamas su pasirinkta programa.", + "common_connectionLost": "Prarastas serverio ryšys
Dabar esate tik skaitymo režime, kol ryšys bus atkurtas.", "type": { "form": "Forma", "teams": "Komandos", "sheet": "Lapas", "contacts": "Kontaktai", - "todo": "Todo", + "todo": "Darbas", "media": "Medija", "file": "Failas", - "whiteboard": "Lenta", - "drive": "CryptDiskas", - "slide": "Prezentacija", + "whiteboard": "Interaktyvioji lenta", + "drive": "„CryptDrive“", + "slide": "Ženklinimo skaidrės", "kanban": "Kanbanas", "poll": "Apklausa", "code": "Kodas", - "pad": "Tekstas" + "pad": "Raiškusis tekstas", + "doc": "Dokumentas", + "presentation": "Pristatymas", + "diagram": "Grafika" }, - "main_title": "CryptPad: lengvai valdomas, bendradarbiavimas realiuoju laiku", + "main_title": "„CryptPad“: nulis žinių, kolektyvinis redagavimas tikruoju laiku", "filePicker_close": "Uždaryti", "filePickerButton": "Įterpkite failą, saugomą „CryptDrive“", "printBackgroundRemove": "Pašalinkite šį foną", From a64a471e49df68ad8f068d3b6028578f189a7be0 Mon Sep 17 00:00:00 2001 From: Weblate Date: Mon, 23 Sep 2024 19:55:08 +0200 Subject: [PATCH 03/49] Translated using Weblate (Russian) Currently translated at 100.0% (1783 of 1783 strings) Co-authored-by: Weblate Co-authored-by: serbul (ifreedomlab.net) Translate-URL: https://weblate.cryptpad.org/projects/cryptpad/app/ru/ Translation: CryptPad/App --- www/common/translations/messages.ru.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.ru.json b/www/common/translations/messages.ru.json index 0bc1fc280..a1d23562b 100644 --- a/www/common/translations/messages.ru.json +++ b/www/common/translations/messages.ru.json @@ -1782,5 +1782,6 @@ "install_instance": "Создайте первую учетную запись администратора, а затем приступайте к настройке этого экземпляра", "admin_onboardingDescPlaceholder": "Текст описания экземпляра", "admin_mfa_confirm_disable": "Вы уверены, что хотите выключить многофакторную аутентификацию (MFA)?", - "admin_mfa_confirm_enable": "Вы уверены, что хотите включить многофакторную аутентификацию (MFA)?" + "admin_mfa_confirm_enable": "Вы уверены, что хотите включить многофакторную аутентификацию (MFA)?", + "team_autoTrim": "Оптимизация (усечение) истории хранилища Команды... Пожалуйста, подождите." } From 2f1206f5bcb080036793955d33e51f9945b99a73 Mon Sep 17 00:00:00 2001 From: Weblate Date: Mon, 23 Sep 2024 19:55:08 +0200 Subject: [PATCH 04/49] Translated using Weblate (Japanese) Currently translated at 100.0% (1783 of 1783 strings) Co-authored-by: Suguru Hirahara Co-authored-by: Weblate Translate-URL: https://weblate.cryptpad.org/projects/cryptpad/app/ja/ Translation: CryptPad/App --- www/common/translations/messages.ja.json | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/www/common/translations/messages.ja.json b/www/common/translations/messages.ja.json index 661582e6e..024c2ce07 100644 --- a/www/common/translations/messages.ja.json +++ b/www/common/translations/messages.ja.json @@ -956,7 +956,7 @@ "settings_ownDriveConfirm": "アカウントのアップグレードには時間がかかるかもしれません。全てのデバイスで再ログインする必要があります。よろしいですか?", "settings_padOpenLinkLabel": "直接リンクを開く機能を有効にする", "settings_padOpenLinkHint": "このオプションを有効にすると、プレビューの吹き出しを表示せず、埋め込んだリンクをクリックして直接開くことができます", - "settings_padOpenLinkTitle": "最初のクリックでリンクを開く", + "settings_padOpenLinkTitle": "1回のクリックでリンクを開く", "settings_padSpellcheckLabel": "リッチテキストのドキュメントでスペルチェックを有効にする", "settings_padWidth": "エディターの最大幅", "settings_codeUseTabs": "タブを使ってインデント(空白スペースの代わりに)", @@ -1289,7 +1289,7 @@ "share_versionHash": "ドキュメントの選択したバージョンを閲覧モードで共有します。それにより、このドキュメントの全てのバージョンへの読み取り専用アクセスも可能になります。", "history_cantRestore": "復元に失敗しました。接続が切れています。", "todo_move": "タスクリストはCryptDriveのカンバン「{0}」に移動しました。", - "info_imprintFlavour": "このインスタンスの管理者に関する法的情報。", + "info_imprintFlavour": "このインスタンスの管理者に関する法的情報", "settings_safeLinkDefault": "セーフリンクは既定で有効になっています。ブラウザーのアドレスバーではなく、 共有メニューを使ってリンクをコピーしてください。", "comments_notification": "{1}でのあなたのコメント「{0}」に対する返信", "infobar_versionHash": "このドキュメントの過去のバージョンを閲覧しています({0})。", @@ -1778,8 +1778,10 @@ "install_instance": "初めに管理者アカウントを作成して、その後にインスタンスのカスタマイズに移ります", "support_legacyButton": "アクティブなチケットを入手", "support_searchLabel": "検索(タイトルまたはチケットのID)", - "support_legacyClear": "このアカウントで削除", + "support_legacyClear": "このアカウントに関して削除", "support_moveActive": "アクティブに移動", "support_userNotification": "新しいサポートチケットまたは回答:{0}", - "install_notes": "
  • このページで最初の管理者アカウントを作成してください。管理者は、ストレージの割合などを含むインスタンスの設定を管理したり、モデレーション用のツールにアクセスしたりできます。
  • あなたのパスワードは、あなたの全ドキュメントと、このインスタンスの管理者特権を暗号化する秘密鍵となります。 パスワードを紛失した場合、データを復元することはできません。
  • コンピューターを共用している場合、作業を完了したら必ずログアウトしてください。ブラウザーのウインドウを閉じるだけでは、第三者によりあなたのアカウントにアクセスされるおそれがあります。
" + "install_notes": "
  • このページで最初の管理者アカウントを作成してください。管理者は、ストレージの割合などを含むインスタンスの設定を管理したり、モデレーション用のツールにアクセスしたりできます。
  • あなたのパスワードは、あなたの全ドキュメントと、このインスタンスの管理者特権を暗号化する秘密鍵となります。 パスワードを紛失した場合、データを復元することはできません。
  • コンピューターを共用している場合、作業を完了したら必ずログアウトしてください。ブラウザーのウインドウを閉じるだけでは、第三者によりあなたのアカウントにアクセスされるおそれがあります。
", + "form_condorcetExtendedDisplay": "各候補が勝利した回数: ", + "team_autoTrim": "チームドライブの履歴を縮小しています…お待ちください。" } From 3d34983bb97b0865d60e0ecd4326724b0404f228 Mon Sep 17 00:00:00 2001 From: Weblate Date: Mon, 23 Sep 2024 19:55:08 +0200 Subject: [PATCH 05/49] Translated using Weblate (Polish) Currently translated at 100.0% (1783 of 1783 strings) Co-authored-by: Magpie Co-authored-by: Weblate Translate-URL: https://weblate.cryptpad.org/projects/cryptpad/app/pl/ Translation: CryptPad/App --- www/common/translations/messages.pl.json | 78 ++++++++++++------------ 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/www/common/translations/messages.pl.json b/www/common/translations/messages.pl.json index e2e34574e..57cf9748d 100644 --- a/www/common/translations/messages.pl.json +++ b/www/common/translations/messages.pl.json @@ -16,7 +16,7 @@ "todo": "Do zrobienia", "media": "Media", "whiteboard": "Tablica", - "drive": "Dysk", + "drive": "CryptDrive", "diagram": "Diagram" }, "disconnected": "Rozłączony", @@ -49,7 +49,7 @@ "poll_userPlaceholder": "Twoje imię", "poll_removeOption": "Jesteś pewien, że chcesz usunąć tę opcję?", "poll_removeUser": "Jesteś pewien, że chcesz usunąć tego użytkownika?", - "poll_descriptionHint": "Opisz swoją ankietę i użyj przycisku ✓ (opublikuj), gdy skończysz.\nOpis może być napisany przy użyciu składni markdown i można w nim osadzać elementy multimedialne z CryptDrive.\nKażdy, kto ma link, może zmienić opis, ale jest to odradzane.", + "poll_descriptionHint": "Opisz swoją ankietę i użyj przycisku ✓ (opublikuj), gdy skończysz.\nW opisie możesz użyć składni markdown oraz osadzać elementy multimedialne z dysku CryptDrive.\nKażda osoba posiadająca link może zmienić opis, co jednak nie jest zalecane.", "header_logoTitle": "Przejdź na stronę główną", "storageStatus": "Pamięć:
Wykorzystałeś {0} z {1}", "upgradeAccount": "Ulepsz swoje konto", @@ -69,14 +69,14 @@ "error": "Błąd", "loading": "Ładowanie...", "newVersionError": "Nowa wersja CryptPad jest dostępna.
Odśwież aby korzystać z nowej wersji lub wciśnij klawisz Esc aby pracować w trybie offline.", - "errorRedirectToHome": "Wciśnij Esc, by wrócić do swojego CryptDrive.", + "errorRedirectToHome": "Wciśnij Esc, by zostać przekierowanym do własnego dysku CryptDrive.", "errorCopy": " Możesz korzystać z aktualnej wersji w trybie tylko do odczytu, klikając Esc.", "invalidHashError": "Dokument, który chcesz zobaczyć ma błędny adres URL.", "chainpadError": "Podczas aktualizacji zawartości wystąpił krytyczny błąd. Dokument wyświetlany jest w trybie tylko do odczytu, aby umożliwić zachowanie wyników pracy.
Wciśnij klawisz Esc aby wyświetlić dokument lub odśwież stronę, by spróbować wrócić do trybu edycji.", "inactiveError": "Ten dokument został usunięty z powodu braku aktywności. Wciśnij klawisz Esc, aby stworzyć nowy dokument.", "deletedError": "Dokument został usunięty i nie jest już dostępny.", "expiredError": "Dokument wygasł i nie jest już dostępny.", - "anonymousStoreDisabled": "Administrator tej instancji wyłączył zapisywanie danych dla niezalogowanych użytkowników. Zaloguj się, aby otrzymać dostęp do aplikacji.", + "anonymousStoreDisabled": "Administrator tej instancji CryptPad wyłączył zapisywanie danych dla niezalogowanych użytkowników. Zaloguj się, aby korzystać z własnego dysku CryptDrive.", "padNotPinnedVariable": "Dokument zostanie usunięty po {4} dniach braku aktywności, {0}zaloguj się{1} lub {2}zarejestruj{3} aby go zachować.", "padNotPinned": "Ten dokument zostanie usunięty po 3 miesiącach braku aktywności, {0}zaloguj się{1} lub {2}zarejestruj{3} aby go zachować.", "onLogout": "Jesteś wylogowany, {0}kliknij tutaj{1} aby się zalogować
lub użyj klawisza Esc aby wyświetlić swój dokument (tryb tylko do odczytu).", @@ -90,7 +90,7 @@ "templateSaved": "Szablon zapisany!", "saveTemplatePrompt": "Wybierz nazwę dla szablonu", "saveTemplateButton": "Zapisz jako szablon", - "uploadButtonTitle": "Prześlij nowy plik do swojego CryptDrive", + "uploadButtonTitle": "Prześlij nowy plik na swój dysk CryptDrive", "uploadFolderButton": "Wgraj folder", "uploadButton": "Prześlij pliki", "newButtonTitle": "Utwórz nowy dokument", @@ -107,9 +107,9 @@ "exportButton": "Eksportuj", "importButton": "Importuj", "pinLimitDrive": "Osiągnięto limit przestrzeni dyskowej.
Nie możesz tworzyć nowych dokumentów.", - "pinLimitNotPinned": "Osiągnięto limit przestrzeni dyskowej.
Dokument nie będzie zapisany na dysku.", + "pinLimitNotPinned": "Osiągnięto limit przestrzeni dyskowej.
Dokument nie będzie zapisany na Twoim CryptDrive.", "pinLimitReachedAlertNoAccounts": "Osiągnięto limit przestrzeni dyskowej", - "pinLimitReachedAlert": "Osiągnięto limit przestrzeni dyskowej. Nowe dokumenty nie będą przechowywane.
Możesz usunąć dokumenty z dysku lub skorzystać z oferty premium aby zwiększyć jego pojemność.", + "pinLimitReachedAlert": "Osiągnięto limit przestrzeni dyskowej. Nowe dokumenty nie będą przechowywane na Twoim dysku CryptDrive.
Możesz usunąć dokumenty ze swojego CryptDrive lub skorzystać z oferty premium aby zwiększyć jego pojemność.", "pinLimitReached": "Osiągnięto limit przestrzeni dyskowej", "formattedKB": "{0} kB", "formattedGB": "{0} GB", @@ -120,9 +120,9 @@ "fm_viewListButton": "Widok listy", "fm_error_cantPin": "Wewnętrzny błąd serwera. Proszę przeładować stronę i spróbować ponownie.", "fm_info_owned": "Jesteś właścicielem wyświetlanych tu dokumentów. Oznacza to, że możesz je trwale usunąć z serwera, kiedy tylko zechcesz. Jeśli to zrobisz, inni użytkownicy nie będą mieli już do nich dostępu.", - "fm_info_sharedFolder": "To jest Folder współdzielony. Nie jesteś zalogowany, więc możesz mieć do niego dostęp tylko w trybie odczytu.
Zarejestruj się lub zaloguj się aby móc zaimportować go do swojego CryptDrive i modyfikować.", + "fm_info_sharedFolder": "To jest folder współdzielony. Nie jesteś zalogowany, więc masz do niego dostęp tylko w trybie do odczytu.
Zarejestruj się lub zaloguj aby móc zaimportować go na swój dysk CryptDrive i modyfikować.", "fm_info_anonymous": "Nie jesteś zalogowany, więc Twoje dokumenty wygasną po {0} dniach. Wyczyszczenie historii przeglądarki może spowodować ich zniknięcie.
Zarejestruj się (dane osobowe nie są wymagane) lubZaloguj się, aby przechowywać je na dysku przez czas nieokreślony.Dowiedz się więcej o zarejestrowanych kontach.", - "fm_info_trash": "Opróżnij swój kosz, aby zwolnić przestrzeń dla danych w swoim CryptDrive.", + "fm_info_trash": "Opróżnij swój kosz, aby zwolnić miejsce na swoim dysku CryptDrive.", "fm_info_recent": "Dokumenty te były ostatnio otwierane lub modyfikowane przez Ciebie lub osoby, z którymi współpracujesz.", "fm_info_template": "Dokumenty te były ostatnio otwierane lub modyfikowane przez Ciebie lub osoby, z którymi współpracujesz.", "fm_info_root": "Utwórz tutaj tyle zagnieżdżonych folderów, ile chcesz, aby uporządkować swoje pliki.", @@ -195,7 +195,7 @@ "profileButton": "Profil", "canvas_imageEmbed": "Dołącz obraz z komputera", "canvas_currentBrush": "Aktualny pędzel", - "canvas_saveToDrive": "Zapisz ten obraz jako plik w swoim CryptDrive", + "canvas_saveToDrive": "Zapisz ten obraz jako plik na swoim dysku CryptDrive", "canvas_widthLabel": "Szerokość: {0}", "canvas_opacityLabel": "Przezroczystość: {0}", "canvas_opacity": "Przezroczystość", @@ -229,7 +229,7 @@ "kanban_item": "Element {0}", "kanban_newBoard": "Nowa tablica", "pad_mediatagOptions": "Właściwości obrazu", - "pad_mediatagImport": "Zapisz w swoim CryptDrive", + "pad_mediatagImport": "Zapisz na swoim CryptDrive", "pad_mediatagPreview": "Podgląd", "pad_mediatagBorder": "Szerokość ramki (w pikselach)", "pad_mediatagRatio": "Zachowuj proporcje", @@ -266,9 +266,9 @@ "tags_add": "Aktualizuj tagi dla wybranych dokumentów", "tags_title": "Tagi (tylko dla Ciebie)", "filePicker_filter": "Filtruj pliki według nazwy", - "filePicker_description": "Wybierz plik z Twojego CryptDrive do osadzenia lub załaduj nowy", + "filePicker_description": "Wybierz plik ze swojego CryptDrive który chcesz osadzić, lub załaduj nowy", "filePicker_close": "Zamknij", - "filePickerButton": "Osadź plik przechowywany w CryptDrive", + "filePickerButton": "Osadź plik przechowywany na dysku CryptDrive", "printBackgroundRemove": "Usuń ten obraz tła", "printBackgroundNoValue": "Nie wyświetlono żadnego obrazu tła", "printBackgroundValue": "Aktualny obraz tła: {0}", @@ -318,7 +318,7 @@ "settings_resetThumbnailsDescription": "Wyczyść wszystkie miniaturki dokumentów przechowywane w przeglądarce.", "settings_resetThumbnailsAction": "Wyczyść", "settings_disableThumbnailsDescription": "Miniaturki są automatycznie tworzone i przechowywane w przeglądarce, gdy odwiedzasz nowy dokument. Możesz wyłączyć tę funkcję tutaj.", - "settings_disableThumbnailsAction": "Wyłączenie tworzenia miniaturek w Twoim CryptDrive", + "settings_disableThumbnailsAction": "Wyłącz tworzenie miniaturek w Twoim CryptDrive", "settings_thumbnails": "Miniaturki", "settings_resetTipsDone": "Wszystkie wskazówki są teraz ponownie widoczne.", "settings_resetTipsButton": "Resetowanie dostępnych wskazówek w CryptDrive", @@ -327,10 +327,10 @@ "settings_resetError": "Nieprawidłowy tekst weryfikacyjny. Twój CryptDrive nie został zmieniony.", "settings_resetDone": "Twój dysk jest teraz pusty!", "settings_resetPrompt": "Ta czynność spowoduje usunięcie wszystkich dokumentów z dysku.
Czy na pewno chcesz kontynuować?
Wpisz \"I love CryptPad\", aby potwierdzić.", - "settings_export_reading": "Czytanie twojego CryptDrive...", + "settings_export_reading": "Wczytywanie Twojego CryptDrive...", "settings_reset": "Usuń wszystkie pliki i foldery z Twojego CryptDrive", "settings_resetButton": "Usuń", - "settings_resetNewTitle": "Wyczyść CryptDrive", + "settings_resetNewTitle": "Uporządkuj CryptDrive", "settings_exportErrorOther": "Wystąpił błąd podczas próby wyeksportowania tego dokumentu: {0}", "settings_exportErrorMissing": "Ten dokument nie jest dostępny na naszych serwerach (wygasł lub został usunięty przez właściciela)", "settings_exportErrorEmpty": "Ten dokument nie może zostać wyeksportowany (pusta lub nieprawidłowa zawartość).", @@ -344,20 +344,20 @@ "settings_exportFailed": "Jeśli pobranie dokumentu wymaga więcej niż 1 minutę, nie zostanie on wyeksportowany. Zostanie wyświetlony link do każdego dokumentu, który nie został wyeksportowany.", "settings_exportDescription": "Zaczekaj, aż pobierzemy i odszyfrujemy Twoje dokumenty. Może to potrwać kilka minut. Zamknięcie karty spowoduje przerwanie tego procesu.", "settings_exportTitle": "Eksportuj swój CryptDrive", - "settings_backup2Confirm": "Spowoduje to pobranie wszystkich dokumentów i plików z Twojego CryptDrive. Jeśli chcesz kontynuować, wybierz nazwę i naciśnij OK", + "settings_backup2Confirm": "Spowoduje to pobranie wszystkich dokumentów i plików z Twojego dysku CryptDrive. Jeśli chcesz kontynuować, wybierz nazwę i naciśnij OK", "settings_backup2": "Pobierz mój CryptDrive", "settings_backupHint2": "Pobierz wszystkie dokumenty znajdujące się na Twoim dysku. Dokumenty zostaną pobrane w formacie czytelnym dla innych aplikacji, jeśli taki format jest dostępny. Jeśli taki format nie jest dostępny, dokumenty zostaną pobrane w formacie odczytywanym przez CryptPad.", "settings_restore": "Przywróć", "settings_backup": "Kopia zapasowa", "settings_backupCategory": "Kopia zapasowa", - "settings_backupHint": "Wykonaj kopię zapasową lub przywróć całą zawartość dysku CryptDrive. Nie będzie on zawierał zawartości Twoich dokumentów, a jedynie klucze dostępu do nich.", + "settings_backupHint": "Wykonaj kopię zapasową lub przywróć całą zawartość swojego dysku CryptDrive. Nie będzie on zawierał zawartości Twoich dokumentów, a jedynie klucze dostępu do nich.", "settings_save": "Zapisz", "settings_title": "Ustawienia", "settings_cat_subscription": "Subskrypcja", "settings_cat_pad": "Tekst sformatowany", "settings_cat_code": "Kod", "settings_cat_cursor": "Kursor", - "settings_cat_drive": "Dysk", + "settings_cat_drive": "Dysk CryptDrive", "settings_cat_account": "Konto", "register_emailWarning3": "Jeśli to rozumiesz i chcesz używać swojego adresu e-mail jako nazwy użytkownika, kliknij OK.", "register_emailWarning2": "Nie będziesz mógł zresetować swojego hasła za pomocą swojego e-maila, tak jak można to zrobić w przypadku innych usług.", @@ -459,7 +459,7 @@ "admin_supportInitHelp": "Twój serwer nie jest jeszcze skonfigurowany do używania skrzynki pocztowej służącej do udzielania pomocy technicznej. Jeśli chcesz, aby skrzynka pocztowa służąca do udzielania pomocy technicznej otrzymywała wiadomości od Twoich użytkowników, powinieneś poprosić administratora serwera o uruchomienie skryptu znajdującego się w \"./scripts/generate-admin-keys.js\", a następnie zapisanie klucza publicznego w pliku \"config.js\" i przesłanie Ci klucza prywatnego.", "admin_cat_support": "Wsparcie", "supportPage": "Wsparcie", - "fm_info_sharedFolderHistory": "To jest tylko historia Twojego folderu współdzielonego: {0}
Twój CryptDrive pozostanie w trybie tylko do odczytu podczas nawigacji.", + "fm_info_sharedFolderHistory": "Historia należy tylko do Twojego folderu współdzielonego: {0}
Twój CryptDrive pozostanie w trybie tylko do odczytu podczas nawigacji.", "notifications_dismiss": "Odrzuć", "share_withFriends": "Udostępnij", "share_linkFriends": "Udostępnij kontaktom", @@ -526,24 +526,24 @@ "crowdfunding_popup_text": "

Potrzebujemy Twojej pomocy!

Aby zapewnić, że CryptPad jest aktywnie rozwijany, rozważ wsparcie projektu poprzez stronę OpenCollective, gdzie możesz zobaczyć nasze nasz Plan działania i Cele Finansowania.", "crowdfunding_button2": "Wspomóż", "crowdfunding_button": "Wspieraj CryptPad", - "autostore_notAvailable": "Aby móc korzystać z tej funkcji, musisz zapisać ten dokument w swoim CryptDrive.", + "autostore_notAvailable": "Aby móc korzystać z tej funkcji, dokument musi znajdować się na Twoim CryptDrive.", "autostore_hide": "Nie zapisuj", "autostore_store": "Zapisz", - "autostore_forceSave": "Zapisz plik w swoim CryptDrive", - "autostore_saved": "Dokument został pomyślnie zapisany w Twoim CryptDrive!", + "autostore_forceSave": "Przechowaj plik na swoim CryptDrive", + "autostore_saved": "Dokument został pomyślnie zapisany na Twoim CryptDrive!", "autostore_error": "Nieoczekiwany błąd: nie udało się zapisać tego dokumentu, proszę spróbować ponownie.", "autostore_settings": "Możesz włączyć automatyczne przechowywanie dokumentów na stronie Ustawienia.", - "autostore_notstored": "Tego {0} nie ma w twoim CryptDrive. Czy chcesz go teraz zapisać?", + "autostore_notstored": "Tego {0} nie ma na Twoim CryptDrive. Czy chcesz go teraz zapisać?", "autostore_pad": "pad", "autostore_sf": "folder", "autostore_file": "plik", "chrome68": "Wygląda na to, że używasz przeglądarki Chrome lub Chromium w wersji 68. Zawiera ona błąd powodujący, że po kilku sekundach strona staje się całkowicie biała lub nie reaguje na kliknięcia. Aby naprawić ten problem, możesz przełączyć się na inną kartę i wrócić do niej lub spróbować przewinąć stronę. Ten błąd powinien zostać naprawiony w następnej wersji przeglądarki.", "convertFolderToSF_confirm": "Ten folder musi zostać przekształcony w folder współdzielony, aby inni mogli go przeglądać. Kontynuować?", "convertFolderToSF_SFChildren": "Ten folder nie może zostać przekształcony na folder współdzielony, ponieważ zawiera już foldery współdzielone. Aby kontynuować, przenieś te foldery współdzielone w inne miejsce.", - "sharedFolders_forget": "Ten dokument jest przechowywany tylko w folderze współdzielonym, nie możesz go przenieść do kosza. Możesz użyć swojego CryptDrive, jeśli chcesz go usunąć.", + "sharedFolders_forget": "Ten dokument jest przechowywany tylko w folderze współdzielonym, nie możesz go przenieść do kosza. Możesz użyć swojego dysku CryptDrive, jeśli chcesz go usunąć.", "features_f_cryptdrive1_note": "Foldery, foldery współdzielone, szablony, tagi", "convertFolderToSF_SFParent": "Tego folderu nie można przekształcić w folder współdzielony w jego bieżącej lokalizacji. Aby kontynuować, przenieś go poza zawierający go folder współdzielony.", - "sharedFolders_share": "Udostępnij ten link innym zarejestrowanym użytkownikom, aby dać im dostęp do udostępnionego folderu. Gdy otworzą oni ten link, udostępniony folder zostanie dodany do ich CryptDrive.", + "sharedFolders_share": "Udostępnij ten link innym zarejestrowanym użytkownikom, aby dać im dostęp do dzielonego folderu. Gdy otworzą ten link, udostępniony folder zostanie dodany do ich CryptDrive.", "sharedFolders_create_owned": "Folder własny", "sharedFolders_create_name": "Nazwa folderu", "settings_cursorShowHint": "Możesz wybrać, czy chcesz widzieć kursor innych użytkowników we współdzielonych dokumentach.", @@ -564,7 +564,7 @@ "share_linkCategory": "Link", "properties_changePasswordButton": "Prześlij", "properties_passwordSuccess": "Hasło zostało pomyślnie zmienione.
Naciśnij OK, aby przeładować i zaktualizować swoje prawa dostępu.", - "properties_passwordWarning": "Hasło zostało pomyślnie zmienione, ale nie udało nam się zaktualizować Twojego CryptDrive o nowe dane. Konieczne może być ręczne usunięcie starej wersji dokumentu.
Naciśnij OK, aby ponownie załadować i zaktualizować prawa dostępu.", + "properties_passwordWarning": "Hasło zostało pomyślnie zmienione, ale nie udało nam się zaktualizować danych na Twoim dysku CryptDrive. Konieczne może być manualne usunięcie starej wersji dokumentu.
Naciśnij OK, aby ponownie załadować stronę i zaktualizować dane dostępowe.", "properties_passwordError": "Wystąpił błąd podczas próby zmiany hasła. Proszę spróbować ponownie.", "properties_passwordSame": "Nowe hasła muszą się różnić od dotychczasowych.", "properties_confirmChange": "Czy jesteś pewien? Zmiana hasła spowoduje usunięcie jego historii. Użytkownicy bez nowego hasła stracą dostęp do tego dokumentu", @@ -881,7 +881,7 @@ "register_registrationIsClosed": "Rejestracja została zamknięta.", "mediatag_defaultImageName": "obraz", "genericCopySuccess": "Skopiowane do schowka", - "toolbar_storeInDrive": "Przechowuj w CryptDrive", + "toolbar_storeInDrive": "Zachowaj w CryptDrive", "calendar_noNotification": "Brak", "calendar_addNotification": "Dodaj przypomnienie", "calendar_notifications": "Przypomnienia", @@ -1054,7 +1054,7 @@ "admin_getlimitsTitle": "Własne limity", "admin_limit": "Obecny limit: {0}", "admin_setlimitButton": "Ustaw limit", - "admin_defaultlimitHint": "Maksymalny limit przechowywania danych w CryptDrive (użytkownicy i zespoły), gdy nie jest stosowana żadna reguła własna", + "admin_defaultlimitHint": "Maksymalny limit przestrzeni na dyskach CryptDrive (użytkownicy i zespoły), gdy nie nadano żadnych reguły niestandardowych", "admin_defaultlimitTitle": "Maksymalny limit przechowywania danych (MB)", "admin_registrationTitle": "Zamknij rejestrację", "admin_registrationHint": "Goście odwiedzający instancję nie mają możliwości stworzenia konta. Zaproszenia mogą być tworzone przez administratorów.", @@ -1074,9 +1074,9 @@ "snapshots_button": "Obrazy dokumentu", "snaphot_title": "Obraz dokumentu", "infobar_versionHash": "Obecnie przeglądasz poprzednią wersję tego dokumentu ({0}).", - "history_restoreDriveDone": "CryptDrive przywrócony", - "history_restoreDrivePrompt": "Czy na pewno chcesz zastąpić aktualną wersję CryptDrive wyświetloną wersją?", - "history_restoreDriveTitle": "Przywrócenie wybranej wersji CryptDrive", + "history_restoreDriveDone": "Przywrócono CryptDrive", + "history_restoreDrivePrompt": "Czy na pewno chcesz zastąpić obecną wersję CryptDrive wyświetlaną wersją?", + "history_restoreDriveTitle": "Przywróć wybraną wersję CryptDrive", "history_userNext": "Następny autor", "history_fastNext": "Następna sesja edycji", "history_userPrev": "Poprzedni autor", @@ -1223,7 +1223,7 @@ "settings_trimHistoryTitle": "Usuń Historię", "trimHistory_noHistory": "Nie można usunąć historii", "trimHistory_currentSize": "Aktualny rozmiar historii: {0}", - "trimHistory_needMigration": "Proszę zaktualizować swój CryptDrive, aby włączyć tę funkcję.", + "trimHistory_needMigration": "Zaktualizuj swój CryptDrive, aby włączyć tę funkcję.", "trimHistory_success": "Historia została usunięta", "trimHistory_error": "Błąd podczas usuwania historii", "trimHistory_getSizeError": "Błąd podczas obliczania rozmiaru historii dysku", @@ -1298,14 +1298,14 @@ "teams_table_generic_view": "Przeglądaj: dostęp do folderów i dokumentów (tylko do odczytu).", "teams_table_generic": "Role i uprawnienia", "teams_table": "Role", - "driveOfflineError": "Twoje połączenie z CryptPad zostało utracone. Zmiany w tym dokumencie nie zostaną zapisane w Twoim CryptDrive. Proszę zamknąć wszystkie zakładki CryptPad i spróbować ponownie w nowym oknie. ", + "driveOfflineError": "Twoje połączenie z CryptPad zostało utracone. Zmiany w tym dokumencie nie zostaną zapisane w Twoim CryptDrive. Zamknij wszystkie zakładki CryptPad i spróbuj ponownie w nowym oknie. ", "properties_passwordSuccessFile": "Hasło zostało pomyślnie zmienione.", - "properties_passwordWarningFile": "Hasło zostało pomyślnie zmienione, ale nie udało nam się zaktualizować Twojego CryptDrive o nowe dane. Może być konieczne ręczne usunięcie starej wersji pliku.", + "properties_passwordWarningFile": "Hasło zostało pomyślnie zmienione, ale nie udało nam się zaktualizować Twojego CryptDrive nowymi danymi. Może być konieczne ręczne usunięcie starej wersji pliku.", "properties_confirmNewFile": "Czy jesteś pewien? Dodanie hasła spowoduje zmianę adresu URL tego pliku. Użytkownicy bez hasła stracą dostęp do tego pliku.", "properties_confirmChangeFile": "Czy jesteś pewien? Użytkownicy bez nowego hasła stracą dostęp do tego pliku.", "password_error_seed": "Dokument nie został znaleziony!
Błąd ten może być spowodowany przez dwa czynniki: albo hasło zostało dodane/zmienione, albo dokument został usunięty z serwera.", "drive_sfPasswordError": "Błędne hasło", - "drive_sfPassword": "Twój udostępniony folder {0} nie jest już dostępny. Został on albo usunięty przez właściciela, albo jest teraz chroniony nowym hasłem. Możesz usunąć ten folder z Twojego CryptDrive, lub odzyskać do niego dostęp używając nowego hasła.", + "drive_sfPassword": "Twój współdzielony folder {0} nie jest już dostępny. Został on albo usunięty przez właściciela, albo jest teraz chroniony nowym hasłem. Możesz usunąć ten folder z Twojego CryptDrive, lub odzyskać do niego dostęp używając nowego hasła.", "team_viewers": "Przeglądający", "settings_codeBrackets": "Automatyczne zamykanie nawiasów", "team_quota": "Limit miejsca Twojego zespołu", @@ -1326,7 +1326,7 @@ "team_listSlot": "Dostępne miejsce dla zespołu", "team_listTitle": "Twoje zespoły", "team_maxTeams": "Każde konto użytkownika może być członkiem tylko {0} zespołów.", - "team_infoContent": "Każdy zespół ma swój własny CryptDrive, limit pamięci, czat i listę członków. Właściciele zespołu mogą usunąć cały zespół, administratorzy mogą zapraszać lub wyrzucać członków, członkowie mogą opuścić zespół.", + "team_infoContent": "Każdy zespół ma swój własny dysk CryptDrive, limit pamięci, czat i listę członków. Właściciele zespołu mogą usunąć cały zespół, administratorzy mogą zapraszać lub wyrzucać członków, członkowie mogą opuścić zespół.", "team_avatarHint": "Maksymalny rozmiar 500kB (png, jpg, jpeg, gif)", "team_avatarTitle": "Awatar zespołu", "team_nameHint": "Podaj nazwę zespołu", @@ -1334,7 +1334,7 @@ "team_members": "Członkowie", "team_admins": "Administratorzy", "team_owner": "Właściciele", - "team_leaveConfirm": "Jeśli opuścisz ten zespół, stracisz dostęp do jego CryptDrive, historii czatu i innych treści. Czy jesteś pewien?", + "team_leaveConfirm": "Jeśli opuścisz ten zespół, stracisz dostęp do jego dysku CryptDrive, historii czatu i innych treści. Czy jesteś pewien?", "team_leaveButton": "Opuść ten zespół", "team_inviteButton": "Zaproś nowych członków", "team_rosterKick": "Wyrzuć z zespołu", @@ -1513,7 +1513,7 @@ "admin_pinLogAvailable": "Dostępny log pinezek", "admin_pinLogArchived": "Log pinezek został zarchiwizowany", "admin_getPinList": "Lista obecnych pinezek", - "og_default": "CryptPad: szyfrowany end-to-end pakiet narzędzi do współpracy", + "og_default": "CryptPad: szyfrowany end-to-end pakiet narzędzi do wspólnej pracy", "calendar_rec_edit": "Powtarzające się wydarzenie", "calendar_str_filter_day": "Dni: {0}", "calendar_rec_weekdays": "Codziennie w weekendy", From a3b951d268a51e79f9facf29e65bf17ca7b735fd Mon Sep 17 00:00:00 2001 From: Weblate Date: Mon, 23 Sep 2024 19:55:08 +0200 Subject: [PATCH 06/49] Translated using Weblate (Basque) Currently translated at 100.0% (1783 of 1783 strings) Co-authored-by: Alexander Gabilondo Co-authored-by: Weblate Translate-URL: https://weblate.cryptpad.org/projects/cryptpad/app/eu/ Translation: CryptPad/App --- www/common/translations/messages.eu.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.eu.json b/www/common/translations/messages.eu.json index e92618366..50ffbce38 100644 --- a/www/common/translations/messages.eu.json +++ b/www/common/translations/messages.eu.json @@ -1780,5 +1780,8 @@ "admin_onboardingOptionsTitle": "Instantziaren aukerak", "admin_onboardingNamePlaceholder": "Instantziaren izenburua", "admin_onboardingDescPlaceholder": "Instantziaren deskribapen testua", - "admin_onboardingOptionsHint": "Mesedez, hautatu aukera egokia zure instantziarako.
Ezarpen hauek geroago alda daitezke administrazio panelean." + "admin_onboardingOptionsHint": "Mesedez, hautatu aukera egokia zure instantziarako.
Ezarpen hauek geroago alda daitezke administrazio panelean.", + "admin_mfa_confirm_disable": "Ziur faktore anitzeko autentifikazioa desgaitu nahi duzula?", + "admin_mfa_confirm_enable": "Ziur faktore anitzeko autentifikazioa gaitu nahi duzula?", + "team_autoTrim": "Taldeko diskoen historia mozten... Itxaron mesedez." } From 724901e9257ae5a1e12f00ad98bc9553b65e35a2 Mon Sep 17 00:00:00 2001 From: Weblate Date: Sun, 29 Sep 2024 19:22:28 +0200 Subject: [PATCH 07/49] Translated using Weblate (Spanish) Currently translated at 87.6% (1562 of 1783 strings) Co-authored-by: Ricardo Garicano Arenas Translate-URL: https://weblate.cryptpad.org/projects/cryptpad/app/es/ Translation: CryptPad/App --- www/common/translations/messages.es.json | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.es.json b/www/common/translations/messages.es.json index 1fa31d646..0892a210c 100644 --- a/www/common/translations/messages.es.json +++ b/www/common/translations/messages.es.json @@ -1556,5 +1556,22 @@ "calendar_rec_warn_updateall": "La regla para repetir este evento ha sido modificada. El primer evento en {0} será mantenido, todos los demás serán sustituidos.", "calendar_rec_warn_update": "La regla para repetir este evento ha sido modificada. Los eventos futuros serán sustituidos.", "calendar_rec_warn_delall": "Este evento ya no se va a repetir. El primer evento en {0} se mantendrá, todos los demás serán eliminados.", - "calendar_rec_warn_del": "Este evento ya no se va a repetir. Los eventos futuros serán eliminados." + "calendar_rec_warn_del": "Este evento ya no se va a repetir. Los eventos futuros serán eliminados.", + "continue": "Continuar", + "team_inviteRole": "Rol inicial", + "team_inviteUses": "Uso(s) permitido(s) para este enlace (0 = sin límite)", + "form_exportJSON": "Exportar a JSON", + "form_alreadyAnsweredMult": "Ha respondido a este formulario el:", + "form_deleteAll": "Borrar todo", + "form_answer_new": "Enviar de nuevo", + "form_allowNotifications": "Notificaciones de nuevas respuestas", + "form_editable_off": "Sólo una vez", + "form_editable_on_del": "Una vez y editar/borrar", + "form_multiple": "Múltiples veces", + "form_multiple_edit": "Múltiples veces y editar/borrar", + "form_editable_str": "Envío", + "team_linkUsesInfinite": "(sin límite de usos)", + "form_settingsButton": "Configuración del formulario", + "form_editable_on": "Una vez y editar", + "form_responseNotification": "Nuevas respuestas a la forma: {0}" } From add436ce615ac5596b232f01d9c6a7384e8009eb Mon Sep 17 00:00:00 2001 From: Weblate Date: Sun, 29 Sep 2024 19:22:28 +0200 Subject: [PATCH 08/49] Translated using Weblate (Polish) Currently translated at 100.0% (1783 of 1783 strings) Co-authored-by: Magpie Co-authored-by: Weblate Translate-URL: https://weblate.cryptpad.org/projects/cryptpad/app/pl/ Translation: CryptPad/App --- www/common/translations/messages.pl.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/www/common/translations/messages.pl.json b/www/common/translations/messages.pl.json index 57cf9748d..705f6a363 100644 --- a/www/common/translations/messages.pl.json +++ b/www/common/translations/messages.pl.json @@ -620,7 +620,7 @@ "features_f_devices_note": "Uzyskaj wszędzie dostęp do CryptDrive za pomocą swojego konta użytkownika", "features_f_devices": "Twoje dokumenty na wszystkich Twoich urządzeniach", "features_f_cryptdrive1": "Pełna funkcjonalność CryptDrive", - "features_f_anon_note": "Z dodatkowymi funkcjami", + "features_f_anon_note": "Z dodatkowymi funkcjonalnościami", "features_f_anon": "Wszystkie funkcje użytkownika-gościa", "features_f_storage0_note": "Dokumenty są usuwane po {0} dniach bezczynności", "features_f_storage0": "Ograniczony czas przechowywania", @@ -1411,7 +1411,7 @@ "support_cat_drives": "Dysk lub zespół", "support_cat_document": "Dokument", "support_cat_abuse": "Zgłoś nadużycie", - "ui_openDirectly": "Ta funkcja nie jest dostępna, gdy CryptPad jest osadzony w innej witrynie. Otworzyć ten dokument w nowej karcie?", + "ui_openDirectly": "Ta funkcjonalność nie jest dostępna, gdy CryptPad jest osadzony w innej witrynie. Otworzyć ten dokument w nowej karcie?", "support_cat_debugging": "Debuguj dane", "support_debuggingDataTitle": "Informacje dotyczące debugowania konta", "support_debuggingDataHint": "Poniższe informacje są zawarte w przesyłanych zgłoszeniach do pomocy technicznej. Żadna z nich nie umożliwia administratorom dostępu do dokumentów użytkownika ani ich odszyfrowania. Informacje te są zaszyfrowane w taki sposób, że tylko administratorzy mogą je odczytać.", From b8332543aa40b0e01f99c73ab0462a5b702cbe9f Mon Sep 17 00:00:00 2001 From: daria Date: Tue, 1 Oct 2024 12:35:22 +0300 Subject: [PATCH 09/49] disable arrow key navigation in the drive while modal is active #1660 --- www/common/common-ui-elements.js | 7 +++---- www/common/drive-ui.js | 4 +++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index ae0dea302..b1a0e6a36 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -2510,13 +2510,11 @@ define([ } else { next(); } - return; - } - if (e.which === 13) { + } + else if (e.which === 13) { if ($container.find('.cp-icons-element-selected').length === 1) { $container.find('.cp-icons-element-selected').click(); } - return; } }); @@ -2525,6 +2523,7 @@ define([ window.setTimeout(function () { modal.show(); $modal.focus(); + next(); }); }; diff --git a/www/common/drive-ui.js b/www/common/drive-ui.js index 135b0eae0..28003d446 100644 --- a/www/common/drive-ui.js +++ b/www/common/drive-ui.js @@ -1045,7 +1045,9 @@ define([ // If the arrow keys aren't caught by another listener before, it means we can // use them to select content in the drive. If that's the case, we'll also // focus the drive container to avoid conflicts with other focused elements - $content.focus(); + if (!$('.cp-modal').is(':visible')) { + $content.focus(); + } var click = function (el) { if (!el) { return; } From e75dd7c5de51e678f6e4f4338378c6587aaefaa0 Mon Sep 17 00:00:00 2001 From: daria Date: Tue, 1 Oct 2024 14:06:32 +0300 Subject: [PATCH 10/49] add `Esc` option to Form description text field #1636 --- www/form/inner.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/www/form/inner.js b/www/form/inner.js index 3428d98b6..911aa1258 100644 --- a/www/form/inner.js +++ b/www/form/inner.js @@ -1097,6 +1097,11 @@ define([ block = h('div.cp-form-edit-options-block', [t]); cm = SFCodeMirror.create("gfm", CMeditor, t); editor = cm.editor; + editor.setOption("extraKeys", { + "Esc": function () { + editor.display.input.blur(); + }, + }); editor.setOption('lineNumbers', true); editor.setOption('lineWrapping', true); editor.setOption('styleActiveLine', true); From 7a06548e1fd503e27924c6a92d2de7ce0fc97ed2 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 2 Oct 2024 12:45:06 +0200 Subject: [PATCH 11/49] lint compliance --- scripts/testcrypto.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/testcrypto.js b/scripts/testcrypto.js index 0ee9d0fb7..470062057 100644 --- a/scripts/testcrypto.js +++ b/scripts/testcrypto.js @@ -39,7 +39,7 @@ console.log(LibSodium.crypto_sign_verify_detached(sig, msg, pub)); console.log('start sodium-native'); a = +new Date(); - for (var i = 0; i < n; i++) { + for (let i = 0; i < n; i++) { SodiumNative.crypto_sign_open(msg, signedMsg, pub); SodiumNative.crypto_sign_verify_detached(sig, msg, pub); } @@ -47,7 +47,7 @@ console.log(LibSodium.crypto_sign_verify_detached(sig, msg, pub)); console.log('start libsodium'); a = +new Date(); - for (var i = 0; i < n; i++) { + for (let i = 0; i < n; i++) { LibSodium.crypto_sign_open(signedMsg, pub); LibSodium.crypto_sign_verify_detached(sig, msg, pub); } @@ -55,7 +55,7 @@ console.log(LibSodium.crypto_sign_verify_detached(sig, msg, pub)); console.log('start tweetnacl'); a = +new Date(); - for (var i = 0; i < n; i++) { + for (let i = 0; i < n; i++) { Nacl.sign.open(signedMsg, pub); Nacl.sign.detached.verify(msg, sig, pub); } From 62fb40e79ba15d066f9e692538e97b543b0fee66 Mon Sep 17 00:00:00 2001 From: David Benque Date: Wed, 2 Oct 2024 14:48:49 +0100 Subject: [PATCH 12/49] Update issue template --- .github/ISSUE_TEMPLATE/bug_resolution.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/ISSUE_TEMPLATE/bug_resolution.yml b/.github/ISSUE_TEMPLATE/bug_resolution.yml index 85f0f639a..b5a3b276e 100644 --- a/.github/ISSUE_TEMPLATE/bug_resolution.yml +++ b/.github/ISSUE_TEMPLATE/bug_resolution.yml @@ -89,6 +89,7 @@ body: label: Version description: What version of CryptPad are you running? options: + - 2024.9.0 - 2024.6.1 - 2024.6.0 - 2024.3.1 From 0d872af27d359e3b05b9bcdffbd24249290c889f Mon Sep 17 00:00:00 2001 From: David Benque Date: Wed, 2 Oct 2024 14:48:58 +0100 Subject: [PATCH 13/49] Update changelog --- CHANGELOG.md | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a07f5aa0a..78d1e234d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,100 @@ SPDX-FileCopyrightText: 2023 XWiki CryptPad Team and cont SPDX-License-Identifier: AGPL-3.0-or-later --> +# Autumn release (2024.9.0) + +## Goals + +This release improves the performance of CryptPad with server optimizations and an optional cryptography plugin. We also include lots of improvements and fixes across various areas. + +## Features + +- Add support for cryptography plugins to replace tweetnacl on the server [#1667](https://github.com/cryptpad/cryptpad/pull/1667) + - We use our [CryptPad Sodium plugin](https://github.com/cryptpad/cryptpad-sodium-plugin) to improve the performance of our flagship instance cryptpad.fr. + - Documentation will be available shortly in the form of a blog post and section in the admin guide. + +## Improvements + +- Server memory improvements [#1543](https://github.com/cryptpad/cryptpad/pull/1543) +- Server optimization when computing metadata [#1566](https://github.com/cryptpad/cryptpad/pull/1566) +- Team roster channels slow down team members accounts [#1614](https://github.com/cryptpad/cryptpad/pull/1614) +- Deployment + - Add example configs for Caddy [#1603](https://github.com/cryptpad/cryptpad/pull/1603) + - Add support for HTTP -> HTTPS (80 -> 443 ports) redirection [#1582](https://github.com/cryptpad/cryptpad/pull/1582) + - Added "git config --add safe.directory" [#1539](https://github.com/cryptpad/cryptpad/pull/1539) +- Add confirmation modal when admins turn on mandatory 2FA [#1552](https://github.com/cryptpad/cryptpad/pull/1552) +- Developers on Windows can now launch their local instance with `npm run windev` + +## Fixes + +- Modals accessibility + - `Shift-Tab` option for `Ctrl-E` modals [#1647](https://github.com/cryptpad/cryptpad/pull/1647) + - Remove focus from disabled elements on modals [#1618](https://github.com/cryptpad/cryptpad/pull/1618) + - `+New` button fixes on Drive [#1610](https://github.com/cryptpad/cryptpad/pull/1610) + - Accessibility improvements to modals [#1563](https://github.com/cryptpad/cryptpad/pull/1563) + - `Ctrl+E` modal fixes [#1559](https://github.com/cryptpad/cryptpad/pull/1559) + - Focus style fixes [#1560](https://github.com/cryptpad/cryptpad/pull/1560) + - Make password change confirmation button responsive on mobile [#1569](https://github.com/cryptpad/cryptpad/pull/1569) +- Calendar + - Fix calendar ownership sharing bug [#1655](https://github.com/cryptpad/cryptpad/pull/1655) + - Calendar modal UI fixes [#1615](https://github.com/cryptpad/cryptpad/pull/1615) + - Make 'New Event' modal appear in user view for small screens [#1583](https://github.com/cryptpad/cryptpad/pull/1583) +- Teams + - Improve Teams card list accessibility [#1585](https://github.com/cryptpad/cryptpad/pull/1585) + - Fix emoji avatar handling and team name overflowing in sidebar teams [#1598](https://github.com/cryptpad/cryptpad/pull/1598) +- Toolbar/menus + - Make code history buttons not overlap on small screens [#1586](https://github.com/cryptpad/cryptpad/pull/1586) + - Fix misaligned/missing file dropdown menu items [#1578](https://github.com/cryptpad/cryptpad/pull/1578) +- Diagram + - Ignore unknown fields in diagram document [#1666](https://github.com/cryptpad/cryptpad/commit/02da76d3de76455a5573dd43d7ef6e68bf62c959) +- Forms + - Fix overflowing check and radio items in form app conditional [#1591](https://github.com/cryptpad/cryptpad/pull/1591) +- Kanban + - fixed a bug that was causing duplicate cards when many editors were collaborating [02da76d](https://github.com/cryptpad/cryptpad/commit/02da76d3de76455a5573dd43d7ef6e68bf62c959) +- OnlyOffice + - OnlyOffice document out of sync with multiple tabs as guest [#1671](https://github.com/cryptpad/cryptpad/issues/1671) +- Miscellaneous + - Fix ownership/sharing issues with password-protected pads [#1565](https://github.com/cryptpad/cryptpad/pull/1565) + - Make performance table responsive for mobile (admin panel) [#1555](https://github.com/cryptpad/cryptpad/pull/1555) + - Fix bash indentation and trailing whitespaces [#1548](https://github.com/cryptpad/cryptpad/pull/1548) + - Drive focus fixes [#1611](https://github.com/cryptpad/cryptpad/pull/1611) + + +## Dependencies + +We upgraded the following packages + +- cryptpad + - chainpad-server to `5.2.2` + - netflux-websocket to `1.2.1` +- third-party + - express to `4.21.0` + - http-proxy-middleware to `3.0.2` + - requirejs to `2.3.7` + - stylelint to `16.9.0` + + +## Upgrade notes + +If you are upgrading from a version older than `2024.6.1` please read the upgrade notes of all versions between yours and `2024.9.0` 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.9.0 +npm ci +npm run install:components +./install-onlyoffice.sh +``` + +3. Restart your server +4. Review your instance's checkup page to ensure that you are passing all tests + + # 2024.6.1 ## Goals From fe481eda295fc96ffc928d3f41f812728bfbabf6 Mon Sep 17 00:00:00 2001 From: mathilde-cryptpad <156299270+mathilde-cryptpad@users.noreply.github.com> Date: Mon, 7 Oct 2024 08:32:38 +0200 Subject: [PATCH 14/49] upgrade Docker Hub version to 2024.9.0 in docker-compose.yml --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 6f5a190f0..b959a25be 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,7 +5,7 @@ --- services: cryptpad: - image: "cryptpad/cryptpad:version-2024.6.1" + image: "cryptpad/cryptpad:version-2024.9.0" hostname: cryptpad environment: From c768665047ef4472ce53c8222cced4b20cd7b6a6 Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 7 Oct 2024 18:22:13 +0200 Subject: [PATCH 15/49] Fix worker substitution issues after crash --- lib/workers/index.js | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/lib/workers/index.js b/lib/workers/index.js index 55487c848..d383cb59b 100644 --- a/lib/workers/index.js +++ b/lib/workers/index.js @@ -152,7 +152,18 @@ Workers.initialize = function (Env, config, _cb) { // default to timing out affter 180s if no explicit timeout is passed var timeout = typeof(opt.timeout) !== 'undefined'? opt.timeout: DEFAULT_QUERY_TIMEOUT; response.expect(txid, cb, timeout); + + delete msg._cb; + delete msg._opt; state.worker.send(msg); + + // Add original callback to message data in case we need + // to resend the command. setTimeout to avoid interfering + // with worker.send + setTimeout(function () { + msg._cb = _cb; + msg._opt = opt; + }); }; var handleResponse = function (state, res) { @@ -237,26 +248,36 @@ Workers.initialize = function (Env, config, _cb) { const cb = response.expectation(txid); if (typeof(cb) !== 'function') { return; } const task = state.tasks[txid]; - if (!(task && task.msg)) { return; } + if (!task) { return; } response.clear(txid); - Log.info('DB_WORKER_RESEND', task.msg); - sendCommand(task.msg, cb); + Log.info('DB_WORKER_RESEND', task); + sendCommand(task, task._cb || cb, task._opt); }); var w = fork(DB_PATH); - initWorker(w, function (err, state) { + initWorker(w, function (err) { if (err) { throw new Error(err); } - workers.push(state); }); }); - worker.on('exit', substituteWorker); - worker.on('close', substituteWorker); + worker.on('exit', function () { + substituteWorker(); + Env.Log.error("DB_WORKER_EXIT", { + pid: state.pid, + }); + }); + worker.on('close', function () { + substituteWorker(); + Env.Log.error("DB_WORKER_CLOSE", { + pid: state.pid, + }); + }); worker.on('error', function (err) { substituteWorker(); Env.Log.error("DB_WORKER_ERROR", { + pid: state.pid, error: err, }); }); From 1dd89159da82b131287dec308fdc9a9fa4f508bb Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 14 Oct 2024 17:16:27 +0200 Subject: [PATCH 16/49] Fix contacts page infinite spinner #1415 --- www/common/outer/messenger.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/www/common/outer/messenger.js b/www/common/outer/messenger.js index 1aec3d51d..ac3c756cd 100644 --- a/www/common/outer/messenger.js +++ b/www/common/outer/messenger.js @@ -382,7 +382,8 @@ define([ } // History cleared while we were offline // ==> we asked for an invalid last known hash - if (parsed.error && parsed.error === "EINVAL") { + if (parsed.error && (parsed.error === "EINVAL" + || parsed.error === "EUNKNOWN")) { setChannelHead(ctx, parsed.channel, '', function () { getChannelMessagesSince(ctx, channel, {}, {}); }); From 3b9b9ea30c9f5537a3729f492825e7eabb27655c Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 16 Oct 2024 16:47:36 +0200 Subject: [PATCH 17/49] Prevent server OOM caused by document history --- lib/hk-util.js | 4 ++ lib/workers/db-worker.js | 62 +++++++++++++++++------------ www/common/outer/async-store.js | 6 +++ www/common/sframe-common-history.js | 24 ++++++++--- www/common/sframe-common-outer.js | 3 ++ 5 files changed, 68 insertions(+), 31 deletions(-) diff --git a/lib/hk-util.js b/lib/hk-util.js index 93c3f9c0e..372c9b290 100644 --- a/lib/hk-util.js +++ b/lib/hk-util.js @@ -773,6 +773,10 @@ const handleGetHistoryRange = function (Env, Server, seq, userId, parsed) { Env.getOlderHistory(channelName, oldestKnownHash, untilHash, desiredMessages, desiredCheckpoint, function (err, toSend) { if (err && err.code !== 'ENOENT') { Env.Log.error("HK_GET_OLDER_HISTORY", err); + Server.send(userId, [0, HISTORY_KEEPER_ID, 'MSG', userId, + JSON.stringify(['HISTORY_RANGE_ERROR', txid, err]) + ]); + return; } if (Array.isArray(toSend)) { diff --git a/lib/workers/db-worker.js b/lib/workers/db-worker.js index 398260d61..4bfae8d55 100644 --- a/lib/workers/db-worker.js +++ b/lib/workers/db-worker.js @@ -33,6 +33,8 @@ Logger.levels.forEach(function (level) { }; }); +const HISTORY_SIZE_LIMIT = 1; // XXX 1GB + var DETAIL = 1000; var round = function (n) { return Math.floor(n * DETAIL) / DETAIL; @@ -322,6 +324,31 @@ const computeMetadata = function (data, cb) { }); }; +const _getFileSize = function (channel, _cb) { + var cb = Util.once(Util.mkAsync(_cb)); + if (!Core.isValidId(channel)) { return void cb('INVALID_CHAN'); } + if (channel.length === HK.STANDARD_CHANNEL_LENGTH || + channel.length === HK.ADMIN_CHANNEL_LENGTH) { + return void store.getChannelSize(channel, function (e, size) { + if (e) { + if (e.code === 'ENOENT') { return void cb(void 0, 0); } + return void cb(e.code); + } + cb(void 0, size); + }); + } + + // 'channel' refers to a file, so you need another API + blobStore.size(channel, function (e, size) { + if (typeof(size) === 'undefined') { return void cb(e); } + cb(void 0, size); + }); +}; + +const getFileSize = function (data, cb) { + _getFileSize(data.channel, cb); +}; + /* getOlderHistory * allows clients to query for all messages until a known hash is read * stores all messages in history as they are read @@ -339,6 +366,7 @@ const getOlderHistory = function (data, cb) { const desiredMessages = data.desiredMessages; const desiredCheckpoint = data.desiredCheckpoint; + var next = () => { var messages = []; var found = false; store.getMessages(channelName, function (msgStr) { @@ -384,6 +412,15 @@ const getOlderHistory = function (data, cb) { } cb(err, toSend); }); + }; + + _getFileSize(channelName, function (err, size) { + if (err) { return void cb(err); } + if (size > HISTORY_SIZE_LIMIT) { + return void cb('HISTORY_TOO_LARGE'); + } + next(); + }); }; const getPinState = function (data, cb) { @@ -401,31 +438,6 @@ const getPinState = function (data, cb) { }); }; -const _getFileSize = function (channel, _cb) { - var cb = Util.once(Util.mkAsync(_cb)); - if (!Core.isValidId(channel)) { return void cb('INVALID_CHAN'); } - if (channel.length === HK.STANDARD_CHANNEL_LENGTH || - channel.length === HK.ADMIN_CHANNEL_LENGTH) { - return void store.getChannelSize(channel, function (e, size) { - if (e) { - if (e.code === 'ENOENT') { return void cb(void 0, 0); } - return void cb(e.code); - } - cb(void 0, size); - }); - } - - // 'channel' refers to a file, so you need another API - blobStore.size(channel, function (e, size) { - if (typeof(size) === 'undefined') { return void cb(e); } - cb(void 0, size); - }); -}; - -const getFileSize = function (data, cb) { - _getFileSize(data.channel, cb); -}; - const _iterateFiles = function (channels, handler, cb) { if (!Array.isArray(channels)) { return cb('INVALID_LIST'); } var L = channels.length; diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 569db9bff..e9eb8226a 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -2343,6 +2343,12 @@ define([ if (completed) { return; } var parsed = parse(msg); if (parsed[1] !== txid) { console.log('bad txid'); return; } + if (parsed[0] === 'HISTORY_RANGE_ERROR') { + cb({ + error: parsed[2] + }); + return; + } if (parsed[0] === 'HISTORY_RANGE_END') { cb({ messages: msgs, diff --git a/www/common/sframe-common-history.js b/www/common/sframe-common-history.js index 943e3f225..55bf2126c 100644 --- a/www/common/sframe-common-history.js +++ b/www/common/sframe-common-history.js @@ -212,6 +212,9 @@ define([ sharedFolder: config.sharedFolder }, function (err, data) { if (err) { return void console.error(err); } + if (data && data.error) { + return void cb(data.error); + } if (!Array.isArray(data.messages)) { return void console.error('Not an array!'); } lastKnownHash = data.lastKnownHash; isComplete = data.isFull; @@ -288,6 +291,14 @@ define([ UI.spinner($hist).get().show(); + let closeAll = () => { + History.state = false; + $hist.hide() + $bottom.show(); + $cke.show(); + $(window).trigger('resize'); + }; + var update = function (newRt) { realtime = newRt; if (!realtime) { return []; } @@ -567,11 +578,7 @@ define([ var onKeyDown, onKeyUp; var closeUI = function () { - History.state = false; - $hist.hide(); - $bottom.show(); - $cke.show(); - $(window).trigger('resize'); + closeAll(); $(window).off('keydown', onKeyDown); $(window).off('keyup', onKeyUp); }; @@ -681,7 +688,12 @@ define([ loadMoreHistory(config, common, function (err, newRt, isFull) { History.readOnly = common.getMetadataMgr().getPrivateData().readOnly; History.loading = false; - if (err) { throw new Error(err); } + if (err) { + console.error(err); + UI.warn(`${Messages.error}: ${err}`); + closeAll(); + return; + } update(newRt); display(); if (isFull) { diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index b4031d155..097bb403b 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -1322,6 +1322,9 @@ define([ toHash: data.toHash, lastKnownHash: data.lastKnownHash }, function (data) { + if (data && data.error) { + return void cb(data); + } cb({ isFull: data.isFull, messages: data.messages.map(function (obj) { From 476ac0265462e9ba3d0a5c6f7939106051cc5297 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 16 Oct 2024 16:56:10 +0200 Subject: [PATCH 18/49] Remove test limit --- lib/workers/db-worker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/workers/db-worker.js b/lib/workers/db-worker.js index 4bfae8d55..28868ba07 100644 --- a/lib/workers/db-worker.js +++ b/lib/workers/db-worker.js @@ -33,7 +33,7 @@ Logger.levels.forEach(function (level) { }; }); -const HISTORY_SIZE_LIMIT = 1; // XXX 1GB +const HISTORY_SIZE_LIMIT = 1024 * 1024 * 1024; // XXX 1GB var DETAIL = 1000; var round = function (n) { From 1aecb4fbab9c09453b85d08af92acbd29e4a4657 Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 17 Oct 2024 17:09:08 +0200 Subject: [PATCH 19/49] Improve plugins options and support monitoring plugin --- lib/api.js | 2 +- lib/hk-util.js | 10 ++++++++++ lib/http-worker.js | 26 ++++++++++++++++++++++++-- lib/rpc.js | 8 ++++++++ lib/workers/db-worker.js | 32 ++++++++++++++++++++++++++++++++ lib/workers/index.js | 33 +++++++++++++++++++++++++++++++++ package-lock.json | 25 +++++++++++++++++++++++++ package.json | 1 + server.js | 36 +++++++++++++++++++++++++++++++++++- 9 files changed, 169 insertions(+), 4 deletions(-) diff --git a/lib/api.js b/lib/api.js index bccf917f8..df3206b1e 100644 --- a/lib/api.js +++ b/lib/api.js @@ -108,7 +108,7 @@ nThen(function (w) { }; // spawn ws server and attach netflux event handlers - let Server = NetfluxSrv.create(new WebSocketServer({ server: Env.httpServer})) + let Server = Env.Server = NetfluxSrv.create(new WebSocketServer({ server: Env.httpServer})) .on('channelClose', historyKeeper.channelClose) .on('channelMessage', historyKeeper.channelMessage) .on('channelOpen', historyKeeper.channelOpen) diff --git a/lib/hk-util.js b/lib/hk-util.js index 93c3f9c0e..167ee5ea0 100644 --- a/lib/hk-util.js +++ b/lib/hk-util.js @@ -321,6 +321,9 @@ const storeMessage = function (Env, channel, msg, isCp, optionalMessageHash, tim // Store the message first, and update the index only once it's stored. // store.messageBin can be async so updating the index first may // result in a wrong cpIndex + try { + Env.plugins.MONITORING.increment(`storeMessage`); + } catch (e) {} nThen((waitFor) => { Env.store.messageBin(id, msgBin, waitFor(function (err) { if (err) { @@ -392,6 +395,10 @@ const storeMessage = function (Env, channel, msg, isCp, optionalMessageHash, tim var msgLength = msgBin.length; index.size += msgLength; + try { + Env.plugins.MONITORING.increment('broadcastMessage', (channel.length-1)); + } catch (e) {} + // handle the next element in the queue next(); @@ -522,6 +529,9 @@ const getHistoryAsync = (Env, channelName, lastKnownHash, beforeHash, handler, c const store = Env.store; let offset = -1; + try { + Env.plugins.MONITORING.increment(`getHistoryAsync`); + } catch (e) {} nThen((waitFor) => { getHistoryOffset(Env, channelName, lastKnownHash, waitFor((err, os) => { if (err) { diff --git a/lib/http-worker.js b/lib/http-worker.js index b93120d74..0d4484d98 100644 --- a/lib/http-worker.js +++ b/lib/http-worker.js @@ -35,7 +35,7 @@ const guid = () => { return Util.guid(response._pending); }; -const sendMessage = (msg, cb, opt) => { +const sendMessage = Env.sendMessage = (msg, cb, opt) => { var txid = guid(); var timeout = (opt && opt.timeout) || DEFAULT_QUERY_TIMEOUT; var obj = { @@ -91,6 +91,23 @@ EVENTS.FLUSH_CACHE = function (data) { }); }; +Object.keys(plugins || {}).forEach(name => { + let plugin = plugins[name]; + if (!plugin.addHttpEvents) { return; } + try { + let events = plugin.addHttpEvents(Env); + Object.keys(events || {}).forEach(cmd => { + // Uppercase event name? + if (cmd !== cmd.toUpperCase()) { return; } + // Event is a function? + if (typeof(events[cmd]) !== "function") { return; } + // Event doesn't already exists? + if (EVENTS[cmd]) { return; } + EVENTS[cmd] = events[cmd]; + }); + } catch (e) {} +}); + process.on('message', msg => { if (!(msg && msg.txid)) { return; } if (msg.type === 'REPLY') { @@ -799,7 +816,12 @@ nThen(function (w) { })); }).nThen(function () { // TODO inform the parent process that this worker is ready - + Object.keys(Env.plugins || {}).forEach(name => { + let plugin = plugins[name]; + if (!plugin.initialize) { return; } + try { plugin.initialize(Env, "http-worker"); } + catch (e) {} + }); }); process.on('uncaughtException', function (err) { diff --git a/lib/rpc.js b/lib/rpc.js index 571272ab1..286604e6d 100644 --- a/lib/rpc.js +++ b/lib/rpc.js @@ -34,6 +34,10 @@ var isUnauthenticateMessage = function (msg) { var handleUnauthenticatedMessage = function (Env, msg, respond, Server, netfluxId) { Env.Log.silly('LOG_RPC', msg[0]); + try { + Env.plugins.MONITORING.increment(`rpc_${msg[0]}`); + } catch (e) {} + var method = UNAUTHENTICATED_CALLS[msg[0]]; method(Env, msg[1], function (err, value) { if (err) { @@ -170,6 +174,10 @@ var rpc = function (Env, Server, userId, data, respond) { var command = msg[1]; + try { + Env.plugins.MONITORING.increment(`rpc_${command}`); + } catch (e) {} + if (command === 'UPLOAD') { // UPLOAD is a special case that skips signature validation // intentional fallthrough behaviour diff --git a/lib/workers/db-worker.js b/lib/workers/db-worker.js index 398260d61..1a6971059 100644 --- a/lib/workers/db-worker.js +++ b/lib/workers/db-worker.js @@ -17,11 +17,18 @@ const Tasks = require("../storage/tasks"); const Nacl = require('tweetnacl/nacl-fast'); const Eviction = require("../eviction"); const CPCrypto = require('../crypto'); +const plugins = require("../plugin-manager"); const Env = { Log: {}, }; +const Monitoring = plugins && plugins.MONITORING; +const monitoringIncrement = key => { + if (!Monitoring || !Monitoring.increment) { return; } + Monitoring.increment(key); +}; + // support the usual log API but pass it to the main process Logger.levels.forEach(function (level) { Env.Log[level] = function (label, info) { @@ -57,6 +64,17 @@ const init = function (config, _cb) { Env.archiveRetentionTime = config.archiveRetentionTime; Env.accountRetentionTime = config.accountRetentionTime; + Env.sendMessage = data => { + process.send(data); + }; + + Object.keys(Env.plugins || {}).forEach(name => { + let plugin = plugins[name]; + if (!plugin.initialize) { return; } + try { plugin.initialize(Env, "db-worker"); } + catch (e) {} + }); + nThen(function (w) { Store.create(config, w(function (err, _store) { if (err) { @@ -277,6 +295,8 @@ const computeIndex = function (data, cb) { const channelName = data.channel; const CB = Util.once(cb); + monitoringIncrement('computeIndex'); + var start = 0; nThen(function (w) { store.getOffset(channelName, w(function (err, obj) { @@ -298,6 +318,7 @@ const computeIndex = function (data, cb) { }); } w.abort(); + monitoringIncrement('computeIndexFromOffset'); CB(err, index); })); }).nThen(function (w) { @@ -306,6 +327,7 @@ const computeIndex = function (data, cb) { store.clearOffset(channelName, w()); }).nThen(function () { // now get the history as though it were the first time + monitoringIncrement('computeIndexFromStart'); computeIndexFromOffset(channelName, 0, CB); }); }; @@ -313,6 +335,7 @@ const computeIndex = function (data, cb) { const computeMetadata = function (data, cb) { const ref = {}; const lineHandler = Meta.createLineHandler(ref, Env.Log.error); + monitoringIncrement('computeMetadata'); return void store.readChannelMetadata(data.channel, lineHandler, function (err) { if (err) { // stream errors? @@ -393,6 +416,7 @@ const getPinState = function (data, cb) { var lineHandler = Pins.createLineHandler(ref, Env.Log.error); // if channels aren't in memory. load them from disk + monitoringIncrement('getPin'); pinStore.readMessagesBin(safeKey, 0, (msgObj, readMore) => { lineHandler(msgObj.buff.toString('utf8')); readMore(); @@ -449,6 +473,7 @@ const _iterateFiles = function (channels, handler, cb) { const getTotalSize = function (data, cb) { var bytes = 0; + monitoringIncrement('getTotalSize'); _iterateFiles(data.channels, function (channel, next) { _getFileSize(channel, function (err, size) { if (!err) { bytes += size; } @@ -494,6 +519,7 @@ const getHashOffset = function (data, cb) { const lastKnownHash = data.hash; if (typeof(lastKnownHash) !== 'string') { return void cb("INVALID_HASH"); } + monitoringIncrement('getHashOffset'); var offset = -1; store.readMessagesBin(channelName, 0, (msgObj, readMore, abort) => { // tryParse return a parsed message or undefined @@ -592,6 +618,8 @@ const completeUpload = function (data, cb) { var arg = data.arg; var size = data.size; + monitoringIncrement('uploadedBlob'); + var method; var label; if (owned) { @@ -671,6 +699,7 @@ const COMMANDS = { }; COMMANDS.INLINE = function (data, cb) { + monitoringIncrement('inlineValidation'); var signedMsg; try { signedMsg = Nacl.util.decodeBase64(data.msg); @@ -695,6 +724,7 @@ COMMANDS.INLINE = function (data, cb) { const checkDetachedSignature = function (signedMsg, signature, publicKey) { if (!(signedMsg && publicKey)) { return false; } + monitoringIncrement('detachedValidation'); var signedBuffer; var pubBuffer; @@ -758,10 +788,12 @@ COMMANDS.HASH_CHANNEL_LIST = function (data, cb) { }; COMMANDS.VALIDATE_ANCESTOR_PROOF = function (data, cb) { + monitoringIncrement('validateAncestorProof'); Block.validateAncestorProof(Env, data && data.proof, cb); }; COMMANDS.VALIDATE_LOGIN_BLOCK = function (data, cb) { + monitoringIncrement('validateLoginBlock'); Block.validateLoginBlock(Env, data.publicKey, data.signature, data.block, cb); }; diff --git a/lib/workers/index.js b/lib/workers/index.js index 55487c848..3e3367e1e 100644 --- a/lib/workers/index.js +++ b/lib/workers/index.js @@ -155,6 +155,20 @@ Workers.initialize = function (Env, config, _cb) { state.worker.send(msg); }; + const pluginsResponses = {}; + Object.keys(Env.plugins || {}).forEach(name => { + let plugin = Env.plugins[name]; + if (!plugin.addWorkerResponses) { return; } + try { + let res = plugin.addWorkerResponses(Env); + Object.keys(res || {}).forEach(key => { + if (typeof(res[key]) !== "function") { return; } + if (pluginsResponses[key]) { return; } + pluginsResponses[key] = res[key]; + }); + } catch (e) {} + }); + var handleResponse = function (state, res) { if (!res) { return; } // handle log messages before checking if it was addressed to your PID @@ -162,12 +176,23 @@ Workers.initialize = function (Env, config, _cb) { if (res.log) { return void handleLog(res.log, res.label, res.info); } + // but don't bother handling things addressed to other processes // since it's basically guaranteed not to work if (res.pid !== PID) { return void Log.error("WRONG_PID", res); } + // handle plugins + if (res.plugin) { + Object.keys(pluginsResponses).some(key => { + if (res.type !== key) { return; } + pluginsResponses[key](res.data); + return true; + }); + return; + } + if (!res.txid) { return; } response.handle(res.txid, [res.error, res.value]); delete state.tasks[res.txid]; @@ -226,7 +251,15 @@ Workers.initialize = function (Env, config, _cb) { handleResponse(state, res); }); + let pid = worker.pid; var substituteWorker = Util.once(function () { + Object.keys(Env.plugins || {}).forEach(name => { + let plugin = Env.plugins[name]; + if (!plugin.onWorkerClosed) { return; } + try { plugin.onWorkerClosed("db-worker", pid); } + catch (e) {} + }); + Env.Log.info("SUBSTITUTE_DB_WORKER", ''); var idx = workers.indexOf(state); if (idx !== -1) { diff --git a/package-lock.json b/package-lock.json index faa58a38e..fd1512409 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,6 +47,7 @@ "open-sans-fontface": "^1.4.0", "openid-client": "^5.4.2", "pako": "^2.1.0", + "prom-client": "^14.2.0", "prompt-confirm": "^2.0.4", "pull-stream": "^3.6.1", "require-css": "0.1.10", @@ -1215,6 +1216,11 @@ "node": ">= 0.6.0" } }, + "node_modules/bintrees": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.2.tgz", + "integrity": "sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw==" + }, "node_modules/body-parser": { "version": "1.20.3", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", @@ -4030,6 +4036,17 @@ "node": ">=0.4.0" } }, + "node_modules/prom-client": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/prom-client/-/prom-client-14.2.0.tgz", + "integrity": "sha512-sF308EhTenb/pDRPakm+WgiN+VdM/T1RaHj1x+MvAuT8UiQP8JmOEbxVqtkbfR4LrvOg5n7ic01kRBDGXjYikA==", + "dependencies": { + "tdigest": "^0.1.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/prompt-actions": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/prompt-actions/-/prompt-actions-3.0.2.tgz", @@ -5384,6 +5401,14 @@ "node": ">=8" } }, + "node_modules/tdigest": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.2.tgz", + "integrity": "sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA==", + "dependencies": { + "bintrees": "1.0.2" + } + }, "node_modules/terminal-paginator": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/terminal-paginator/-/terminal-paginator-2.0.2.tgz", diff --git a/package.json b/package.json index c7cc84e99..7091ad676 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "open-sans-fontface": "^1.4.0", "openid-client": "^5.4.2", "pako": "^2.1.0", + "prom-client": "^14.2.0", "prompt-confirm": "^2.0.4", "pull-stream": "^3.6.1", "require-css": "0.1.10", diff --git a/server.js b/server.js index f240b1cd9..0bff20dca 100644 --- a/server.js +++ b/server.js @@ -25,6 +25,13 @@ var app = Express(); } }()); +Object.keys(Env.plugins || {}).forEach(name => { + let plugin = Env.plugins[name]; + if (!plugin.initialize) { return; } + try { plugin.initialize(Env, "main"); } + catch (e) {} +}); + var COMMANDS = {}; COMMANDS.LOG = function (msg, cb) { @@ -49,6 +56,25 @@ COMMANDS.GET_PROFILING_DATA = function (msg, cb) { cb(void 0, Env.bytesWritten); }; +Object.keys(Env.plugins || {}).forEach(name => { + let plugin = Env.plugins[name]; + if (!plugin.addMainCommands) { return; } + try { + let commands = plugin.addMainCommands(Env); + Object.keys(commands || {}).forEach(cmd => { + // Uppercase command name? + if (cmd !== cmd.toUpperCase()) { return; } + // Command is a function? + if (typeof(commands[cmd]) !== "function") { return; } + // Command doesn't already exists? + if (COMMANDS[cmd]) { return; } + + COMMANDS[cmd] = commands[cmd]; + }); + } catch (e) {} +}); + + nThen(function (w) { require("./lib/log").create(config, w(function (_log) { Env.Log = _log; @@ -93,6 +119,7 @@ nThen(function (w) { var launchWorker = (online) => { var worker = Cluster.fork(workerState); + var pid = worker.process.pid; worker.on('online', () => { online(); }); @@ -122,6 +149,13 @@ nThen(function (w) { }); worker.on('exit', (code, signal) => { + Object.keys(Env.plugins || {}).forEach(name => { + let plugin = Env.plugins[name]; + if (!plugin.onWorkerClosed) { return; } + try { plugin.onWorkerClosed("http-worker", pid); } + catch (e) {} + }); + if (!signal && code === 0) { return; } // relaunch http workers if they crash Env.Log.error('HTTP_WORKER_EXIT', { @@ -147,7 +181,7 @@ nThen(function (w) { }); }; - var broadcast = (command, data/*, cb*/) => { + var broadcast = Env.broadcast = (command, data/*, cb*/) => { for (const worker of Object.values(Cluster.workers)) { sendCommand(worker, command, data /*, cb */); } From efb90652154d0b0b9e650be1fcba132f6ffe3927 Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 31 Oct 2024 13:20:46 +0100 Subject: [PATCH 20/49] Update dependencies --- package-lock.json | 54 +++++++++++++++++++++-------------------------- package.json | 8 +++---- 2 files changed, 28 insertions(+), 34 deletions(-) diff --git a/package-lock.json b/package-lock.json index faa58a38e..62b17c3f2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,20 +19,20 @@ "chainpad-crypto": "^0.2.5", "chainpad-listmap": "^1.1.0", "chainpad-netflux": "^1.2.0", - "chainpad-server": "^5.2.2", + "chainpad-server": "^5.2.3", "ckeditor": "npm:ckeditor4@~4.22.1", "codemirror": "^5.19.0", "components-font-awesome": "^4.6.3", - "cookie-parser": "^1.4.6", + "cookie-parser": "^1.4.7", "croppie": "^2.5.0", "dragula": "3.7.2", "drawio": "github:cryptpad/drawio-npm#npm-21.8.2+5", - "express": "~4.21.0", + "express": "~4.21.1", "file-saver": "1.3.1", "fs-extra": "^7.0.0", "get-folder-size": "^2.0.1", "html2canvas": "^1.4.0", - "http-proxy-middleware": "^3.0.2", + "http-proxy-middleware": "^3.0.3", "hyper-json": "~1.4.0", "jquery": "3.6.0", "json.sortify": "~2.1.0", @@ -1414,15 +1414,9 @@ } }, "node_modules/chainpad-server": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/chainpad-server/-/chainpad-server-5.2.2.tgz", - "integrity": "sha512-fUCffhnd8PlO92A6cYH5lSIiiI6bpJymP0yC3O2KI+4NPyxFK7I2iuadMrC7RzK3eAI1w72Y1nbMN8rQImppoQ==", - "dependencies": { - "nthen": "0.1.8", - "pull-stream": "^3.6.9", - "stream-to-pull-stream": "^1.7.3", - "ws": "^3.3.1" - } + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/chainpad-server/-/chainpad-server-5.2.3.tgz", + "integrity": "sha512-QH4PFXR051jK/t2dF1nw6f3HZQ/c/kO3Pcz2hWY7qAximQ7KF7vGseEJE2Q7xb40Y00F1+25gLBha4v6cUNdZw==" }, "node_modules/chainpad/node_modules/json.sortify": { "version": "2.2.2", @@ -1570,19 +1564,19 @@ } }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "engines": { "node": ">= 0.6" } }, "node_modules/cookie-parser": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz", - "integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==", + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz", + "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==", "dependencies": { - "cookie": "0.4.1", + "cookie": "0.7.2", "cookie-signature": "1.0.6" }, "engines": { @@ -1590,9 +1584,9 @@ } }, "node_modules/cookie-parser/node_modules/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "engines": { "node": ">= 0.6" } @@ -2187,16 +2181,16 @@ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" }, "node_modules/express": { - "version": "4.21.0", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", - "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -2747,9 +2741,9 @@ } }, "node_modules/http-proxy-middleware": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-3.0.2.tgz", - "integrity": "sha512-fBLFpmvDzlxdckwZRjM0wWtwDZ4KBtQ8NFqhrFKoEtK4myzuiumBuNTxD+F4cVbXfOZljIbrynmvByofDzT7Ag==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-3.0.3.tgz", + "integrity": "sha512-usY0HG5nyDUwtqpiZdETNbmKtw3QQ1jwYFZ9wi5iHzX2BcILwQKtYDJPo7XHTsu5Z0B2Hj3W9NNnbd+AjFWjqg==", "dependencies": { "@types/http-proxy": "^1.17.15", "debug": "^4.3.6", diff --git a/package.json b/package.json index c7cc84e99..a7007ea6f 100644 --- a/package.json +++ b/package.json @@ -22,20 +22,20 @@ "chainpad-crypto": "^0.2.5", "chainpad-listmap": "^1.1.0", "chainpad-netflux": "^1.2.0", - "chainpad-server": "^5.2.2", + "chainpad-server": "^5.2.3", "ckeditor": "npm:ckeditor4@~4.22.1", "codemirror": "^5.19.0", "components-font-awesome": "^4.6.3", - "cookie-parser": "^1.4.6", + "cookie-parser": "^1.4.7", "croppie": "^2.5.0", "dragula": "3.7.2", "drawio": "github:cryptpad/drawio-npm#npm-21.8.2+5", - "express": "~4.21.0", + "express": "~4.21.1", "file-saver": "1.3.1", "fs-extra": "^7.0.0", "get-folder-size": "^2.0.1", "html2canvas": "^1.4.0", - "http-proxy-middleware": "^3.0.2", + "http-proxy-middleware": "^3.0.3", "hyper-json": "~1.4.0", "jquery": "3.6.0", "json.sortify": "~2.1.0", From e22d3c812cf8c6c95906eb4afe28b20f3b8050da Mon Sep 17 00:00:00 2001 From: DianaXWiki <139217939+DianaXWiki@users.noreply.github.com> Date: Thu, 31 Oct 2024 18:48:22 +0200 Subject: [PATCH 21/49] Add changes to async --- customize.dist/pages/index.js | 61 +++++++++++++++++++++++++++++--- www/admin/inner.js | 65 +++++++++++++++++++---------------- www/common/extensions.js | 9 ++++- 3 files changed, 101 insertions(+), 34 deletions(-) diff --git a/customize.dist/pages/index.js b/customize.dist/pages/index.js index b732d2558..f827b2541 100644 --- a/customize.dist/pages/index.js +++ b/customize.dist/pages/index.js @@ -167,13 +167,66 @@ define([ let popup = h('div.cp-extensions-popups'); let utils = { h, Util, Hash }; - Extensions.getExtensions('HOMEPAGE_POPUP').forEach(ext => { - if (typeof(ext.check) === "function" && !ext.check()) { return; } - ext.getContent(utils, content => { - $(popup).append(h('div.cp-extensions-popup', content)); + + Extensions.getExtensions('HOMEPAGE_POPUP').forEach(_ext => { + _ext.then(ext => { + ext.getContent(utils, content => { + $(popup).append(h('div.cp-extensions-popup', content)); + resolve(); + }); }); }); + common.getExtensions('ADMIN_CATEGORY').forEach(_ext => { + console.log("category") + _ext.then(ext => { + console.log(ext); + if (!ext || !ext.id || !ext.name || !ext.content) { + return console.error('Invalid extension point', 'ADMIN_CATEGORY', ext); + } + if (categories[ext.id]) { + return console.error('Extension point ID already used', ext); + } + console.log("inside category") + categories[ext.id] = { + icon: ext.icon, + name: ext.name, + content: ext.content + }; + }).catch(error => console.error("Error loading ADMIN_CATEGORY extension:", error)); + }); + + common.getExtensions('ADMIN_ITEM').forEach(_ext => { + console.log("item") + _ext.then(ext => { + console.log("Loading ADMIN_ITEM extension:", ext); // Added log for debugging + if (!ext || !ext.id || typeof(ext.getContent) !== "function") { + return console.error('Invalid extension point', 'ADMIN_ITEM', ext); + } + if (sidebar.hasItem(ext.id)) { + return console.error('Extension point ID already used', ext); + } + + sidebar.addItem(ext.id, cb => { + console.log("inside sidebar") + ext.getContent(common, blocks, utils, content => { + if (!content) { + console.warn("Content is undefined for extension:", ext.id); // Added war + } + console.log("inside getContent: ", content); + cb(content); + }); + }, { + noTitle: !ext.title, + noHint: !ext.description, + title: ext.title, + hint: ext.description + }); + }).catch(error => console.error("Error loading ADMIN_ITEM extension:", error)); + }); + + + return [ h('div#cp-main', [ Pages.infopageTopbar(), diff --git a/www/admin/inner.js b/www/admin/inner.js index a7b587266..71f4be310 100644 --- a/www/admin/inner.js +++ b/www/admin/inner.js @@ -172,19 +172,22 @@ define([ const blocks = sidebar.blocks; // EXTENSION_POINT:ADMIN_CATEGORY - common.getExtensions('ADMIN_CATEGORY').forEach(ext => { - if (!ext || !ext.id || !ext.name || !ext.content) { - return console.error('Invalid extension point', 'ADMIN_CATEGORY', ext); - } - if (categories[ext.id]) { - return console.error('Extension point ID already used', ext); - } - console.error(ext); - categories[ext.id] = { - icon: ext.icon, - name: ext.name, - content: ext.content - }; + common.getExtensions('ADMIN_CATEGORY').forEach(_ext => { + _ext.then(ext => { + console.log(ext) + if (!ext || !ext.id || !ext.name || !ext.content) { + return console.error('Invalid extension point', 'ADMIN_CATEGORY', ext); + } + if (categories[ext.id]) { + return console.error('Extension point ID already used', ext); + } + //console.error(ext); + categories[ext.id] = { + icon: ext.icon, + name: ext.name, + content: ext.content + }; + }).catch(error => console.error("Error loading ADMIN_CATEGORY extension:", error)); }); const flushCache = (cb) => { @@ -3926,24 +3929,28 @@ define([ let utils = { h, Util, Hash }; - common.getExtensions('ADMIN_ITEM').forEach(ext => { - if (!ext || !ext.id || typeof(ext.getContent) !== "function") { - return console.error('Invalid extension point', 'ADMIN_CATEGORY', ext); - } - if (sidebar.hasItem(ext.id)) { - return console.error('Extension point ID already used', ext); - } + common.getExtensions('ADMIN_ITEM').forEach(_ext => { + _ext.then(ext => { + console.log(ext); + if (!ext || !ext.id || typeof(ext.getContent) !== "function") { + return console.error('Invalid extension point', 'ADMIN_CATEGORY', ext); + } + if (sidebar.hasItem(ext.id)) { + return console.error('Extension point ID already used', ext); + } - sidebar.addItem(ext.id, cb => { - ext.getContent(common, blocks, utils, content => { - cb(content); + sidebar.addItem(ext.id, cb => { + ext.getContent(common, blocks, utils, content => { + console.log("Generated content for", ext.id, ":", content); + cb(content); + }); + }, { + noTitle: !ext.title, + noHint: !ext.description, + title: ext.title, + hint: ext.description }); - }, { - noTitle: !ext.title, - noHint: !ext.description, - title: ext.title, - hint: ext.description - }); + }).catch(error => console.error("Error loading ADMIN_CATEGORY extension:", error)); }); diff --git a/www/common/extensions.js b/www/common/extensions.js index 1a0a7d040..f7fda6311 100644 --- a/www/common/extensions.js +++ b/www/common/extensions.js @@ -10,7 +10,14 @@ define([ ext.getExtensions = id => { let e = ext[id]; if (!Array.isArray(e)) { e = []; } - return e; + return e.map(_ext => { + return new Promise((resolve, reject) => { + if (typeof(ext.check) !== "function") { return void resolve(_ext); } + ext.check().then(() => { + resolve(_ext); + }).catch(reject); + }); + }); }; if (!Array.isArray(Extensions) || !Extensions.length) { return ext; } From 16c0b7374d6bfbbcd5c8cd5a9200bfba0d086eee Mon Sep 17 00:00:00 2001 From: DianaXWiki <139217939+DianaXWiki@users.noreply.github.com> Date: Thu, 31 Oct 2024 18:59:33 +0200 Subject: [PATCH 22/49] Add more checks for check function --- www/common/extensions.js | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/www/common/extensions.js b/www/common/extensions.js index f7fda6311..72755c34b 100644 --- a/www/common/extensions.js +++ b/www/common/extensions.js @@ -11,11 +11,22 @@ define([ let e = ext[id]; if (!Array.isArray(e)) { e = []; } return e.map(_ext => { - return new Promise((resolve, reject) => { - if (typeof(ext.check) !== "function") { return void resolve(_ext); } - ext.check().then(() => { + return new Promise((resolve) => { + if (typeof _ext.check === "function") { + const checkResult = _ext.check(); + if (checkResult && typeof checkResult.then === "function") { + checkResult.then(() => { + resolve(_ext); + }).catch(() => { + console.error("Check failed for extension:", _ext); + resolve(null); + }); + } else { + resolve(_ext); + } + } else { resolve(_ext); - }).catch(reject); + } }); }); }; From c35bd01da89209686cf1f566d0210033c99a72b5 Mon Sep 17 00:00:00 2001 From: Kai Biebel <38378574+seclution@users.noreply.github.com> Date: Fri, 1 Nov 2024 15:32:14 +0100 Subject: [PATCH 23/49] Fix example-code-typo --- www/common/application_config_internal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/application_config_internal.js b/www/common/application_config_internal.js index 662db522c..07a7c2f80 100644 --- a/www/common/application_config_internal.js +++ b/www/common/application_config_internal.js @@ -132,7 +132,7 @@ define(function() { // en: "Hello world", // fr: "Bonjour le monde", // de: "Hallo Welt", - // "pt-br": "Olá Mundo"< + // "pt-br": "Olá Mundo" }; /* Cryptpad apps use a common API to display notifications to users From 2b25ae027a212a94fe09b383f9fc749a4ae86fc2 Mon Sep 17 00:00:00 2001 From: DianaXWiki <139217939+DianaXWiki@users.noreply.github.com> Date: Sat, 2 Nov 2024 14:59:38 +0200 Subject: [PATCH 24/49] Fix admin_category not showing problem --- customize.dist/pages/index.js | 60 ++++------------------------------- www/admin/inner.js | 46 ++++++++++++++------------- www/common/extensions.js | 34 +++++++++++--------- 3 files changed, 50 insertions(+), 90 deletions(-) diff --git a/customize.dist/pages/index.js b/customize.dist/pages/index.js index f827b2541..43e2b44d5 100644 --- a/customize.dist/pages/index.js +++ b/customize.dist/pages/index.js @@ -170,62 +170,16 @@ define([ Extensions.getExtensions('HOMEPAGE_POPUP').forEach(_ext => { _ext.then(ext => { - ext.getContent(utils, content => { - $(popup).append(h('div.cp-extensions-popup', content)); - resolve(); - }); + if (ext) { + ext.getContent(utils, content => { + $(popup).append(h('div.cp-extensions-popup', content)); + }); + } + }).catch(error => { + console.error(error); }); }); - common.getExtensions('ADMIN_CATEGORY').forEach(_ext => { - console.log("category") - _ext.then(ext => { - console.log(ext); - if (!ext || !ext.id || !ext.name || !ext.content) { - return console.error('Invalid extension point', 'ADMIN_CATEGORY', ext); - } - if (categories[ext.id]) { - return console.error('Extension point ID already used', ext); - } - console.log("inside category") - categories[ext.id] = { - icon: ext.icon, - name: ext.name, - content: ext.content - }; - }).catch(error => console.error("Error loading ADMIN_CATEGORY extension:", error)); - }); - - common.getExtensions('ADMIN_ITEM').forEach(_ext => { - console.log("item") - _ext.then(ext => { - console.log("Loading ADMIN_ITEM extension:", ext); // Added log for debugging - if (!ext || !ext.id || typeof(ext.getContent) !== "function") { - return console.error('Invalid extension point', 'ADMIN_ITEM', ext); - } - if (sidebar.hasItem(ext.id)) { - return console.error('Extension point ID already used', ext); - } - - sidebar.addItem(ext.id, cb => { - console.log("inside sidebar") - ext.getContent(common, blocks, utils, content => { - if (!content) { - console.warn("Content is undefined for extension:", ext.id); // Added war - } - console.log("inside getContent: ", content); - cb(content); - }); - }, { - noTitle: !ext.title, - noHint: !ext.description, - title: ext.title, - hint: ext.description - }); - }).catch(error => console.error("Error loading ADMIN_ITEM extension:", error)); - }); - - return [ h('div#cp-main', [ diff --git a/www/admin/inner.js b/www/admin/inner.js index 71f4be310..250aaa24d 100644 --- a/www/admin/inner.js +++ b/www/admin/inner.js @@ -172,23 +172,25 @@ define([ const blocks = sidebar.blocks; // EXTENSION_POINT:ADMIN_CATEGORY - common.getExtensions('ADMIN_CATEGORY').forEach(_ext => { - _ext.then(ext => { - console.log(ext) - if (!ext || !ext.id || !ext.name || !ext.content) { - return console.error('Invalid extension point', 'ADMIN_CATEGORY', ext); - } - if (categories[ext.id]) { - return console.error('Extension point ID already used', ext); - } - //console.error(ext); - categories[ext.id] = { - icon: ext.icon, - name: ext.name, - content: ext.content - }; - }).catch(error => console.error("Error loading ADMIN_CATEGORY extension:", error)); - }); + async function processExtensions(id) { + const extensions = await common.getExtensions(id); + extensions.forEach(_ext => { + _ext.then(ext => { + if (!ext || !ext.id || !ext.name || !ext.content) { + return console.error('Invalid extension point', 'ADMIN_CATEGORY', ext); + } + if (categories[ext.id]) { + return console.error('Extension point ID already used', ext); + } + categories[ext.id] = { + icon: ext.icon, + name: ext.name, + content: ext.content + }; + }) + }) + } + const flushCache = (cb) => { cb = cb || function () {}; @@ -3930,15 +3932,14 @@ define([ h, Util, Hash }; common.getExtensions('ADMIN_ITEM').forEach(_ext => { + // console.log("item") _ext.then(ext => { - console.log(ext); if (!ext || !ext.id || typeof(ext.getContent) !== "function") { return console.error('Invalid extension point', 'ADMIN_CATEGORY', ext); } if (sidebar.hasItem(ext.id)) { return console.error('Extension point ID already used', ext); } - sidebar.addItem(ext.id, cb => { ext.getContent(common, blocks, utils, content => { console.log("Generated content for", ext.id, ":", content); @@ -3953,9 +3954,10 @@ define([ }).catch(error => console.error("Error loading ADMIN_CATEGORY extension:", error)); }); - - - sidebar.makeLeftside(categories); + (async () => { + await processExtensions('ADMIN_CATEGORY'); + sidebar.makeLeftside(categories); + })(); }; diff --git a/www/common/extensions.js b/www/common/extensions.js index 72755c34b..9081b257f 100644 --- a/www/common/extensions.js +++ b/www/common/extensions.js @@ -11,22 +11,26 @@ define([ let e = ext[id]; if (!Array.isArray(e)) { e = []; } return e.map(_ext => { - return new Promise((resolve) => { - if (typeof _ext.check === "function") { - const checkResult = _ext.check(); - if (checkResult && typeof checkResult.then === "function") { - checkResult.then(() => { - resolve(_ext); - }).catch(() => { - console.error("Check failed for extension:", _ext); - resolve(null); - }); - } else { - resolve(_ext); - } - } else { - resolve(_ext); + return new Promise((resolve, reject) => { + // If there's no check function, resolve immediately + if (typeof _ext.check !== "function") { + return resolve(_ext); } + const checkResult = _ext.check(); + + checkResult + .then((extPassed) => { + if (!extPassed) { + // Reject if the check didn't pass + resolve(null); + } else { + // Extension passed the check + resolve(_ext); + } + }) + .catch((error) => { + reject(error); + }); }); }); }; From e851e723e098ae0b5e1dd2b0ccbf85aedb5eb315 Mon Sep 17 00:00:00 2001 From: DianaXWiki <139217939+DianaXWiki@users.noreply.github.com> Date: Mon, 4 Nov 2024 14:00:47 +0200 Subject: [PATCH 25/49] Add getExtensionsSync for admin panel extensions --- www/admin/inner.js | 75 +++++++++++++++---------------------- www/common/extensions.js | 20 ++++++++++ www/common/sframe-common.js | 1 + 3 files changed, 52 insertions(+), 44 deletions(-) diff --git a/www/admin/inner.js b/www/admin/inner.js index 250aaa24d..465371b0d 100644 --- a/www/admin/inner.js +++ b/www/admin/inner.js @@ -172,24 +172,20 @@ define([ const blocks = sidebar.blocks; // EXTENSION_POINT:ADMIN_CATEGORY - async function processExtensions(id) { - const extensions = await common.getExtensions(id); - extensions.forEach(_ext => { - _ext.then(ext => { - if (!ext || !ext.id || !ext.name || !ext.content) { - return console.error('Invalid extension point', 'ADMIN_CATEGORY', ext); - } - if (categories[ext.id]) { - return console.error('Extension point ID already used', ext); - } - categories[ext.id] = { - icon: ext.icon, - name: ext.name, - content: ext.content - }; - }) - }) - } + common.getExtensionsSync('ADMIN_CATEGORY').forEach(ext => { + if (!ext || !ext.id || !ext.name || !ext.content) { + return console.error('Invalid extension point', 'ADMIN_CATEGORY', ext); + } + if (categories[ext.id]) { + return console.error('Extension point ID already used', ext); + } + console.error(ext); + categories[ext.id] = { + icon: ext.icon, + name: ext.name, + content: ext.content + }; + }); const flushCache = (cb) => { @@ -3931,36 +3927,27 @@ define([ let utils = { h, Util, Hash }; - common.getExtensions('ADMIN_ITEM').forEach(_ext => { - // console.log("item") - _ext.then(ext => { - if (!ext || !ext.id || typeof(ext.getContent) !== "function") { - return console.error('Invalid extension point', 'ADMIN_CATEGORY', ext); - } - if (sidebar.hasItem(ext.id)) { - return console.error('Extension point ID already used', ext); - } - sidebar.addItem(ext.id, cb => { - ext.getContent(common, blocks, utils, content => { - console.log("Generated content for", ext.id, ":", content); - cb(content); - }); - }, { - noTitle: !ext.title, - noHint: !ext.description, - title: ext.title, - hint: ext.description + common.getExtensionsSync('ADMIN_ITEM').forEach(ext => { + if (!ext || !ext.id || typeof(ext.getContent) !== "function") { + return console.error('Invalid extension point', 'ADMIN_CATEGORY', ext); + } + if (sidebar.hasItem(ext.id)) { + return console.error('Extension point ID already used', ext); + } + sidebar.addItem(ext.id, cb => { + ext.getContent(common, blocks, utils, content => { + cb(content); }); - }).catch(error => console.error("Error loading ADMIN_CATEGORY extension:", error)); + }, { + noTitle: !ext.title, + noHint: !ext.description, + title: ext.title, + hint: ext.description + }); }); - (async () => { - await processExtensions('ADMIN_CATEGORY'); - sidebar.makeLeftside(categories); - })(); + sidebar.makeLeftside(categories); }; - - var updateStatus = APP.updateStatus = function (cb) { sFrameChan.query('Q_ADMIN_RPC', { cmd: 'INSTANCE_STATUS', diff --git a/www/common/extensions.js b/www/common/extensions.js index 9081b257f..9f0ca2f92 100644 --- a/www/common/extensions.js +++ b/www/common/extensions.js @@ -35,6 +35,26 @@ define([ }); }; + ext.getExtensionsSync = id => { + let e = ext[id]; + if (!Array.isArray(e)) { e = []; } + + return e.map(_ext => { + if (typeof _ext.check !== "function") { + return _ext; + } + + const extPassed = _ext.check(); + + if (extPassed) { + return _ext; + } else { + return null; + } + }).filter(ext => ext !== null); + }; + + if (!Array.isArray(Extensions) || !Extensions.length) { return ext; } let all = Extensions.slice(); diff --git a/www/common/sframe-common.js b/www/common/sframe-common.js index c297b5273..8310deb27 100644 --- a/www/common/sframe-common.js +++ b/www/common/sframe-common.js @@ -778,6 +778,7 @@ define([ }; funcs.getExtensions = Ext.getExtensions; + funcs.getExtensionsSync = Ext.getExtensionsSync; funcs.mailbox = {}; From 5381ef9604321b44301abd03eb5f21ed17a37372 Mon Sep 17 00:00:00 2001 From: DianaXWiki <139217939+DianaXWiki@users.noreply.github.com> Date: Mon, 4 Nov 2024 14:27:28 +0200 Subject: [PATCH 26/49] Better handling of failed check function --- www/common/extensions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/extensions.js b/www/common/extensions.js index 9f0ca2f92..dd7e9b97f 100644 --- a/www/common/extensions.js +++ b/www/common/extensions.js @@ -22,7 +22,7 @@ define([ .then((extPassed) => { if (!extPassed) { // Reject if the check didn't pass - resolve(null); + undefined (resolve()); } else { // Extension passed the check resolve(_ext); From 3765dc8c132d7b1499477269b19905bacc374512 Mon Sep 17 00:00:00 2001 From: daria Date: Mon, 4 Nov 2024 14:28:42 +0200 Subject: [PATCH 27/49] change iframe title #1606 --- www/common/sframe-common-outer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index b4031d155..1839babfc 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -78,7 +78,7 @@ define([ requireConfig.urlArgs + '#' + encodeURIComponent(JSON.stringify(req))); $i.attr('allowfullscreen', 'true'); $i.attr('allow', 'clipboard-write'); - $i.attr('title', 'iframe'); + $i.attr('title', 'Main Content'); $('iframe-placeholder').after($i).remove(); // This is a cheap trick to avoid loading sframe-channel in parallel with the From 6b80d35527c82d6e83fe93edf099a4dd9a0af9d5 Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 4 Nov 2024 18:12:04 +0100 Subject: [PATCH 28/49] Fix merge issue --- lib/workers/db-worker.js | 2 +- lib/workers/index.js | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/workers/db-worker.js b/lib/workers/db-worker.js index 1a6971059..4f20c76a8 100644 --- a/lib/workers/db-worker.js +++ b/lib/workers/db-worker.js @@ -68,7 +68,7 @@ const init = function (config, _cb) { process.send(data); }; - Object.keys(Env.plugins || {}).forEach(name => { + Object.keys(plugins || {}).forEach(name => { let plugin = plugins[name]; if (!plugin.initialize) { return; } try { plugin.initialize(Env, "db-worker"); } diff --git a/lib/workers/index.js b/lib/workers/index.js index 3e3367e1e..70965d9f5 100644 --- a/lib/workers/index.js +++ b/lib/workers/index.js @@ -177,12 +177,6 @@ Workers.initialize = function (Env, config, _cb) { return void handleLog(res.log, res.label, res.info); } - // but don't bother handling things addressed to other processes - // since it's basically guaranteed not to work - if (res.pid !== PID) { - return void Log.error("WRONG_PID", res); - } - // handle plugins if (res.plugin) { Object.keys(pluginsResponses).some(key => { @@ -193,6 +187,12 @@ Workers.initialize = function (Env, config, _cb) { return; } + // but don't bother handling things addressed to other processes + // since it's basically guaranteed not to work + if (res.pid !== PID) { + return void Log.error("WRONG_PID", res); + } + if (!res.txid) { return; } response.handle(res.txid, [res.error, res.value]); delete state.tasks[res.txid]; From 7c25a1a3b943094e529849b53e0d1237397c10bf Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 5 Nov 2024 14:17:03 +0100 Subject: [PATCH 29/49] Update chainpad-server --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index ebad7c905..98ab7b729 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,7 @@ "chainpad-crypto": "^0.2.5", "chainpad-listmap": "^1.1.0", "chainpad-netflux": "^1.2.0", - "chainpad-server": "^5.2.3", + "chainpad-server": "^5.2.4", "ckeditor": "npm:ckeditor4@~4.22.1", "codemirror": "^5.19.0", "components-font-awesome": "^4.6.3", @@ -1420,9 +1420,9 @@ } }, "node_modules/chainpad-server": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/chainpad-server/-/chainpad-server-5.2.3.tgz", - "integrity": "sha512-QH4PFXR051jK/t2dF1nw6f3HZQ/c/kO3Pcz2hWY7qAximQ7KF7vGseEJE2Q7xb40Y00F1+25gLBha4v6cUNdZw==" + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/chainpad-server/-/chainpad-server-5.2.4.tgz", + "integrity": "sha512-f4eErhcmIE67vfN9Dkfh0hX/IZDWERmfjdcfPEesXIHKu441jA84H0autvTAFsMTSPimlil7eeGnx4GLBVrR5Q==" }, "node_modules/chainpad/node_modules/json.sortify": { "version": "2.2.2", diff --git a/package.json b/package.json index 46536560a..8ec3e888c 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "chainpad-crypto": "^0.2.5", "chainpad-listmap": "^1.1.0", "chainpad-netflux": "^1.2.0", - "chainpad-server": "^5.2.3", + "chainpad-server": "^5.2.4", "ckeditor": "npm:ckeditor4@~4.22.1", "codemirror": "^5.19.0", "components-font-awesome": "^4.6.3", From f4ec472b67fec452d35ec8ce2d5b2cf8400e8bd1 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 5 Nov 2024 14:20:31 +0100 Subject: [PATCH 30/49] Remove dependency --- package-lock.json | 25 ------------------------- package.json | 1 - 2 files changed, 26 deletions(-) diff --git a/package-lock.json b/package-lock.json index 98ab7b729..cbe23d1b6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,7 +47,6 @@ "open-sans-fontface": "^1.4.0", "openid-client": "^5.4.2", "pako": "^2.1.0", - "prom-client": "^14.2.0", "prompt-confirm": "^2.0.4", "pull-stream": "^3.6.1", "require-css": "0.1.10", @@ -1216,11 +1215,6 @@ "node": ">= 0.6.0" } }, - "node_modules/bintrees": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.2.tgz", - "integrity": "sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw==" - }, "node_modules/body-parser": { "version": "1.20.3", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", @@ -4030,17 +4024,6 @@ "node": ">=0.4.0" } }, - "node_modules/prom-client": { - "version": "14.2.0", - "resolved": "https://registry.npmjs.org/prom-client/-/prom-client-14.2.0.tgz", - "integrity": "sha512-sF308EhTenb/pDRPakm+WgiN+VdM/T1RaHj1x+MvAuT8UiQP8JmOEbxVqtkbfR4LrvOg5n7ic01kRBDGXjYikA==", - "dependencies": { - "tdigest": "^0.1.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/prompt-actions": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/prompt-actions/-/prompt-actions-3.0.2.tgz", @@ -5395,14 +5378,6 @@ "node": ">=8" } }, - "node_modules/tdigest": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.2.tgz", - "integrity": "sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA==", - "dependencies": { - "bintrees": "1.0.2" - } - }, "node_modules/terminal-paginator": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/terminal-paginator/-/terminal-paginator-2.0.2.tgz", diff --git a/package.json b/package.json index 8ec3e888c..f4a3d4386 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,6 @@ "open-sans-fontface": "^1.4.0", "openid-client": "^5.4.2", "pako": "^2.1.0", - "prom-client": "^14.2.0", "prompt-confirm": "^2.0.4", "pull-stream": "^3.6.1", "require-css": "0.1.10", From e7f381644565c723168d56f33bbacb1800bcab56 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 5 Nov 2024 16:41:21 +0100 Subject: [PATCH 31/49] Rewrite monitoring try..catch --- lib/hk-util.js | 12 +++--------- lib/rpc.js | 8 ++------ 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/lib/hk-util.js b/lib/hk-util.js index 167ee5ea0..03b6bd287 100644 --- a/lib/hk-util.js +++ b/lib/hk-util.js @@ -321,9 +321,7 @@ const storeMessage = function (Env, channel, msg, isCp, optionalMessageHash, tim // Store the message first, and update the index only once it's stored. // store.messageBin can be async so updating the index first may // result in a wrong cpIndex - try { - Env.plugins.MONITORING.increment(`storeMessage`); - } catch (e) {} + Env.plugins?.MONITORING?.increment(`storeMessage`); nThen((waitFor) => { Env.store.messageBin(id, msgBin, waitFor(function (err) { if (err) { @@ -395,9 +393,7 @@ const storeMessage = function (Env, channel, msg, isCp, optionalMessageHash, tim var msgLength = msgBin.length; index.size += msgLength; - try { - Env.plugins.MONITORING.increment('broadcastMessage', (channel.length-1)); - } catch (e) {} + Env.plugins?.MONITORING?.increment('broadcastMessage', (channel.length-1)); // handle the next element in the queue next(); @@ -529,9 +525,7 @@ const getHistoryAsync = (Env, channelName, lastKnownHash, beforeHash, handler, c const store = Env.store; let offset = -1; - try { - Env.plugins.MONITORING.increment(`getHistoryAsync`); - } catch (e) {} + Env.plugins?.MONITORING?.increment(`getHistoryAsync`); nThen((waitFor) => { getHistoryOffset(Env, channelName, lastKnownHash, waitFor((err, os) => { if (err) { diff --git a/lib/rpc.js b/lib/rpc.js index 286604e6d..c28c5210a 100644 --- a/lib/rpc.js +++ b/lib/rpc.js @@ -34,9 +34,7 @@ var isUnauthenticateMessage = function (msg) { var handleUnauthenticatedMessage = function (Env, msg, respond, Server, netfluxId) { Env.Log.silly('LOG_RPC', msg[0]); - try { - Env.plugins.MONITORING.increment(`rpc_${msg[0]}`); - } catch (e) {} + Env.plugins?.MONITORING?.increment(`rpc_${msg[0]}`); var method = UNAUTHENTICATED_CALLS[msg[0]]; method(Env, msg[1], function (err, value) { @@ -174,9 +172,7 @@ var rpc = function (Env, Server, userId, data, respond) { var command = msg[1]; - try { - Env.plugins.MONITORING.increment(`rpc_${command}`); - } catch (e) {} + Env.plugins?.MONITORING?.increment(`rpc_${command}`); if (command === 'UPLOAD') { // UPLOAD is a special case that skips signature validation From 7a9cb07bb85fbcf1a797a7b8d62cd35cbfb0f4cf Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 5 Nov 2024 18:44:57 +0100 Subject: [PATCH 32/49] Improve tools for monitoring plugin --- lib/workers/db-worker.js | 21 ++++++++++++++++++++- lib/workers/index.js | 12 ++++++++++++ server.js | 1 + 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/lib/workers/db-worker.js b/lib/workers/db-worker.js index 4f20c76a8..e6af79d62 100644 --- a/lib/workers/db-worker.js +++ b/lib/workers/db-worker.js @@ -797,6 +797,19 @@ COMMANDS.VALIDATE_LOGIN_BLOCK = function (data, cb) { Block.validateLoginBlock(Env, data.publicKey, data.signature, data.block, cb); }; +Object.keys(plugins || {}).forEach(name => { + let plugin = plugins[name]; + if (!plugin.addWorkerCommands) { return; } + try { + let events = plugin.addWorkerCommands(Env); + Object.keys(events || {}).forEach(cmd => { + if (typeof(events[cmd]) !== "function") { return; } + if (COMMANDS[cmd]) { return; } + COMMANDS[cmd] = events[cmd]; + }); + } catch (e) {} +}); + process.on('message', function (data) { if (!data || !data.txid || !data.pid) { return void process.send({ @@ -805,6 +818,13 @@ process.on('message', function (data) { }); } + const command = COMMANDS[data.command]; + + // Command broadcasted to all workers: no callback expected + if (data.type === 'broadcast') { + return void command(data); + } + const cb = function (err, value) { process.send({ error: Util.serializeError(err), @@ -822,7 +842,6 @@ process.on('message', function (data) { }); } - const command = COMMANDS[data.command]; if (typeof(command) !== 'function') { return void cb("E_BAD_COMMAND"); } diff --git a/lib/workers/index.js b/lib/workers/index.js index 70965d9f5..7ddbf93cf 100644 --- a/lib/workers/index.js +++ b/lib/workers/index.js @@ -315,6 +315,18 @@ Workers.initialize = function (Env, config, _cb) { })); }); }).nThen(function () { + Env.broadcastWorkerCommand = (data) => { + workers.forEach(state => { + state.worker.send({ + type: 'broadcast', + pid: PID, + command: data.command, + txid: data.txid + }); + }); + return workers; + }; + Env.computeIndex = function (Env, channel, cb) { Env.store.getWeakLock(channel, function (next) { sendCommand({ diff --git a/server.js b/server.js index 0bff20dca..407f10f43 100644 --- a/server.js +++ b/server.js @@ -185,6 +185,7 @@ nThen(function (w) { for (const worker of Object.values(Cluster.workers)) { sendCommand(worker, command, data /*, cb */); } + return Object.values(Cluster.workers); }; var throttledEnvChange = Util.throttle(function () { From 7ffba04aadabf63a399ed40c5158d850a2650aa8 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 5 Nov 2024 18:47:14 +0100 Subject: [PATCH 33/49] Fix TypeError with monitoring plugin --- lib/http-worker.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/http-worker.js b/lib/http-worker.js index 0d4484d98..9cb88ada0 100644 --- a/lib/http-worker.js +++ b/lib/http-worker.js @@ -71,6 +71,7 @@ EVENTS.ENV_UPDATE = function (data /*, cb */) { Env = JSON.parse(data); Env.Log = Log; Env.plugins = plugins; + Env.sendMessage = sendMessage; Env.incrementBytesWritten = function () {}; } catch (err) { Log.error('HTTP_WORKER_ENV_UPDATE', Util.serializeError(err)); From f033ea0b1d60d2b6cd3bea2da2625342d0b60c5b Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 13 Nov 2024 16:22:09 +0100 Subject: [PATCH 34/49] Add UIElements to plugins utils --- www/admin/inner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/admin/inner.js b/www/admin/inner.js index 465371b0d..c8342a6f7 100644 --- a/www/admin/inner.js +++ b/www/admin/inner.js @@ -3925,7 +3925,7 @@ define([ // EXTENSION_POINT:ADMIN_ITEM let utils = { - h, Util, Hash + h, Util, Hash, UIElements }; common.getExtensionsSync('ADMIN_ITEM').forEach(ext => { if (!ext || !ext.id || typeof(ext.getContent) !== "function") { From efc60655f3a1087a841b8343da3dbe8805124e58 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 13 Nov 2024 17:35:07 +0100 Subject: [PATCH 35/49] Upgrade package.json --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index cbe23d1b6..5eda45ce6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cryptpad", - "version": "2024.9.0", + "version": "2024.9.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "cryptpad", - "version": "2024.9.0", + "version": "2024.9.1", "license": "AGPL-3.0+", "dependencies": { "@mcrowe/minibloom": "^0.2.0", diff --git a/package.json b/package.json index f4a3d4386..1432c3c16 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "cryptpad", "description": "a collaborative office suite that is end-to-end encrypted and open-source", - "version": "2024.9.0", + "version": "2024.9.1", "license": "AGPL-3.0+", "repository": { "type": "git", From ee8591e0404592e9e95ef5e15839c643a118696e Mon Sep 17 00:00:00 2001 From: daria Date: Tue, 19 Nov 2024 14:30:27 +0200 Subject: [PATCH 36/49] remove title attribute as it does not improve screen reader navigation --- www/common/sframe-common-outer.js | 1 - 1 file changed, 1 deletion(-) diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index 1839babfc..c5d0582d4 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -78,7 +78,6 @@ define([ requireConfig.urlArgs + '#' + encodeURIComponent(JSON.stringify(req))); $i.attr('allowfullscreen', 'true'); $i.attr('allow', 'clipboard-write'); - $i.attr('title', 'Main Content'); $('iframe-placeholder').after($i).remove(); // This is a cheap trick to avoid loading sframe-channel in parallel with the From 4e83540d49b9bca03da1a9f55e657b1bce4abab4 Mon Sep 17 00:00:00 2001 From: yflory Date: Fri, 22 Nov 2024 11:25:51 +0100 Subject: [PATCH 37/49] Fix closed tickets remaining in the Inbox tab --- www/common/outer/support.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/www/common/outer/support.js b/www/common/outer/support.js index 1e18c6442..912fa5d23 100644 --- a/www/common/outer/support.js +++ b/www/common/outer/support.js @@ -531,6 +531,11 @@ define([ if (last.sender) { entry.lastAdmin = !last.sender.blockLocation; } + if (last.close) { + doc.tickets.closed[data.channel] = entry; + delete doc.tickets.active[data.channel]; + notifyClient(ctx, true, 'UPDATE_TICKET', data.channel); + } /* let senderKey = last.sender && last.sender.edPublic; if (senderKey) { @@ -589,7 +594,9 @@ define([ doc.tickets.closed[data.channel] = entry; delete doc.tickets.active[data.channel]; delete doc.tickets.pending[data.channel]; - cb({closed: true}); + Realtime.whenRealtimeSyncs(ctx.adminDoc.realtime, function () { + cb({closed: true}); + }); }); }); }; From b4292dcd851fbedcea3a251a1be1127763a045aa Mon Sep 17 00:00:00 2001 From: daria Date: Tue, 3 Dec 2024 12:04:43 +0200 Subject: [PATCH 38/49] disable arrow keys while a modal is opened #1660 --- www/common/drive-ui.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/www/common/drive-ui.js b/www/common/drive-ui.js index 28003d446..4b2d2b119 100644 --- a/www/common/drive-ui.js +++ b/www/common/drive-ui.js @@ -1045,9 +1045,7 @@ define([ // If the arrow keys aren't caught by another listener before, it means we can // use them to select content in the drive. If that's the case, we'll also // focus the drive container to avoid conflicts with other focused elements - if (!$('.cp-modal').is(':visible')) { - $content.focus(); - } + $content.focus(); var click = function (el) { if (!el) { return; } @@ -1062,6 +1060,11 @@ define([ $elements.index($selection.last()[0]); var length = $elements.length; if (length === 0) { return; } + + if ($('.cp-modal').is(':visible')) { + return; + } + // List mode if (getViewMode() === "list") { if (e.which === 40) { click($elements.get(Math.min(lastIndex+1, length -1))); } From 9b253eb98aafdab22eba922a06b0efcfa80d7b4f Mon Sep 17 00:00:00 2001 From: daria Date: Tue, 3 Dec 2024 12:14:49 +0200 Subject: [PATCH 39/49] fix arrow key bug --- www/common/drive-ui.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/www/common/drive-ui.js b/www/common/drive-ui.js index 4b2d2b119..16576ca58 100644 --- a/www/common/drive-ui.js +++ b/www/common/drive-ui.js @@ -990,6 +990,9 @@ define([ // Arrow keys to modify the selection var onWindowKeydown = function (e) { if (!$content.is(':visible')) { return; } + if ($('.cp-modal').is(':visible')) { + return; + } var $searchBar = $tree.find('#cp-app-drive-tree-search-input'); if (document.activeElement && document.activeElement.nodeName === 'INPUT') { return; } if ($searchBar.is(':focus') && $searchBar.val()) { return; } @@ -1061,10 +1064,6 @@ define([ var length = $elements.length; if (length === 0) { return; } - if ($('.cp-modal').is(':visible')) { - return; - } - // List mode if (getViewMode() === "list") { if (e.which === 40) { click($elements.get(Math.min(lastIndex+1, length -1))); } From 7d33f13f54582dfb5680d0828470ce9e0e31e780 Mon Sep 17 00:00:00 2001 From: daria Date: Tue, 3 Dec 2024 13:30:34 +0200 Subject: [PATCH 40/49] create function to simulate click on Enter key --- www/common/drive-ui.js | 67 +++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 31 deletions(-) diff --git a/www/common/drive-ui.js b/www/common/drive-ui.js index 135b0eae0..c5bb2f8f6 100644 --- a/www/common/drive-ui.js +++ b/www/common/drive-ui.js @@ -2968,6 +2968,16 @@ define([ }); UI.openCustomModal(m); }; + + function triggerEnter(selector, $context) { + $context.find(selector).on('keypress', function (event) { + if (event.which === 13) { // enter + event.preventDefault(); + $(this).trigger('click'); // the keypress event triggers the click event + } + }); + } + var addNewPadHandlers = function ($block, isInRoot) { // Handlers if (isInRoot) { @@ -2983,56 +2993,51 @@ define([ refresh(); }; $block.find('a.cp-app-drive-new-folder, li.cp-app-drive-new-folder') - .on('click keypress', function (event) { - if (event.type === 'click' || (event.type === 'keypress' && event.which === 13)) { - event.preventDefault(); - manager.addFolder(currentPath, null, onCreated); - } + .on('click', function (event) { + event.preventDefault(); + manager.addFolder(currentPath, null, onCreated); }); + triggerEnter('a.cp-app-drive-new-folder, li.cp-app-drive-new-folder', $block); if (!APP.disableSF && !manager.isInSharedFolder(currentPath)) { $block.find('a.cp-app-drive-new-shared-folder, li.cp-app-drive-new-shared-folder') - .on('click keypress', function (event) { - if (event.type === 'click' || (event.type === 'keypress' && event.which === 13)) { - event.preventDefault(); - addSharedFolderModal(function (obj) { - if (!obj) { return; } - manager.addSharedFolder(currentPath, obj, refresh); - }); - } + .on('click', function (event) { + event.preventDefault(); + addSharedFolderModal(function (obj) { + if (!obj) { return; } + manager.addSharedFolder(currentPath, obj, refresh); + }); }); + triggerEnter('a.cp-app-drive-new-shared-folder, li.cp-app-drive-new-shared-folder', $block); } $block.find('a.cp-app-drive-new-fileupload, li.cp-app-drive-new-fileupload') - .on('click keypress', function (event) { - if (event.type === 'click' || (event.type === 'keypress' && event.which === 13)) { - event.preventDefault(); - showUploadFilesModal(); - } + .on('click', function (event) { + event.preventDefault(); + showUploadFilesModal(); }); + triggerEnter('a.cp-app-drive-new-fileupload, li.cp-app-drive-new-fileupload', $block); $block.find('a.cp-app-drive-new-folderupload, li.cp-app-drive-new-folderupload') - .on('click keypress', function (event) { - if (event.type === 'click' || (event.type === 'keypress' && event.which === 13)) { - event.preventDefault(); - showUploadFolderModal(); - } + .on('click', function (event) { + event.preventDefault(); + showUploadFolderModal(); }); + triggerEnter('a.cp-app-drive-new-folderupload, li.cp-app-drive-new-folderupload', $block); $block.find('a.cp-app-drive-new-link, li.cp-app-drive-new-link') - .on('click keypress', function (event) { - if (event.type === 'click' || (event.type === 'keypress' && event.which === 13)) { - event.preventDefault(); - showLinkModal(); - } + .on('click', function (event) { + event.preventDefault(); + showLinkModal(); }); + triggerEnter('a.cp-app-drive-new-link, li.cp-app-drive-new-link', $block); } $block.find('a.cp-app-drive-new-doc, li.cp-app-drive-new-doc') - .on('click auxclick keypress', function (event) { - if (event.type === 'click' || event.type === 'auxclick' || (event.type === 'keypress' && event.which === 13)) - { + .on('click auxclick', function (event) { + if (event.type === 'click' || event.type === 'auxclick') { event.preventDefault(); var type = $(this).attr('data-type') || 'pad'; var path = manager.isPathIn(currentPath, [TRASH]) ? '' : currentPath; openIn(type, path, APP.team); } }); + triggerEnter('a.cp-app-drive-new-doc, li.cp-app-drive-new-doc', $block); }; var getNewPadOptions = function (isInRoot) { var options = []; From fccbe9f922b92b044677bc7d1b47fd50f4ef0e8c Mon Sep 17 00:00:00 2001 From: daria Date: Wed, 4 Dec 2024 12:26:42 +0200 Subject: [PATCH 41/49] change syntax --- www/common/drive-ui.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/www/common/drive-ui.js b/www/common/drive-ui.js index c5bb2f8f6..2fd256886 100644 --- a/www/common/drive-ui.js +++ b/www/common/drive-ui.js @@ -2969,14 +2969,14 @@ define([ UI.openCustomModal(m); }; - function triggerEnter(selector, $context) { + var triggerEnter = function (selector, $context) { $context.find(selector).on('keypress', function (event) { if (event.which === 13) { // enter event.preventDefault(); $(this).trigger('click'); // the keypress event triggers the click event } }); - } + }; var addNewPadHandlers = function ($block, isInRoot) { // Handlers From 610414dc18a930a369a78da797cdd759dd3307ac Mon Sep 17 00:00:00 2001 From: daria Date: Wed, 4 Dec 2024 12:39:05 +0200 Subject: [PATCH 42/49] clean unnecessary changes --- www/common/common-ui-elements.js | 1 + www/common/drive-ui.js | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index b1a0e6a36..a2c3b709d 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -2514,6 +2514,7 @@ define([ else if (e.which === 13) { if ($container.find('.cp-icons-element-selected').length === 1) { $container.find('.cp-icons-element-selected').click(); + return; } } }); diff --git a/www/common/drive-ui.js b/www/common/drive-ui.js index 16576ca58..db2811fff 100644 --- a/www/common/drive-ui.js +++ b/www/common/drive-ui.js @@ -1063,7 +1063,6 @@ define([ $elements.index($selection.last()[0]); var length = $elements.length; if (length === 0) { return; } - // List mode if (getViewMode() === "list") { if (e.which === 40) { click($elements.get(Math.min(lastIndex+1, length -1))); } From 8262a0eb7bfaaf519a7bdcfbff0decabfbdd0a57 Mon Sep 17 00:00:00 2001 From: daria Date: Wed, 4 Dec 2024 12:59:51 +0200 Subject: [PATCH 43/49] clean unnecessary changes --- www/common/common-ui-elements.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index a2c3b709d..c615f3fba 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -2510,13 +2510,14 @@ define([ } else { next(); } + return; } - else if (e.which === 13) { + if (e.which === 13) { if ($container.find('.cp-icons-element-selected').length === 1) { $container.find('.cp-icons-element-selected').click(); - return; } } + return; }); From 6cc1908627a787eaff25c106e9c6fa1c2f4e0a4d Mon Sep 17 00:00:00 2001 From: daria Date: Wed, 4 Dec 2024 13:01:14 +0200 Subject: [PATCH 44/49] clean unnecessary changes --- www/common/common-ui-elements.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index c615f3fba..f4c21b05c 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -2511,13 +2511,13 @@ define([ next(); } return; - } + } if (e.which === 13) { if ($container.find('.cp-icons-element-selected').length === 1) { $container.find('.cp-icons-element-selected').click(); } + return; } - return; }); From e0ba719c0e597306ff00c8700de46f0b46bfd3f3 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 4 Dec 2024 12:06:20 +0100 Subject: [PATCH 45/49] Update eslintignore and gitignore --- .eslintignore | 3 +++ .gitignore | 2 ++ 2 files changed, 5 insertions(+) diff --git a/.eslintignore b/.eslintignore index 8a1297856..bcd65baeb 100644 --- a/.eslintignore +++ b/.eslintignore @@ -16,6 +16,9 @@ www/accounts www/worker www/todo +*worker.bundle.js +_build + #lib/plugins/ www/common/hyperscript.js diff --git a/.gitignore b/.gitignore index bac376dcd..013a3e931 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,8 @@ www/common/onlyoffice/v* /onlyoffice-conf/ /onlyoffice-dist/ +_build + # ---> Node # Logs logs From 758d6a6c9187e1a98c142d7ae180d0cf5e00c452 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 4 Dec 2024 12:06:52 +0100 Subject: [PATCH 46/49] lint compliance --- www/common/sframe-common-history.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/sframe-common-history.js b/www/common/sframe-common-history.js index 55bf2126c..e711d5265 100644 --- a/www/common/sframe-common-history.js +++ b/www/common/sframe-common-history.js @@ -293,7 +293,7 @@ define([ let closeAll = () => { History.state = false; - $hist.hide() + $hist.hide(); $bottom.show(); $cke.show(); $(window).trigger('resize'); From 3b8bbd4ff6fe1f74e6af7c50cae2c82f980a16e4 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 4 Dec 2024 13:08:28 +0100 Subject: [PATCH 47/49] Fix npm warnings --- package-lock.json | 770 ++++++++++++++++++++-------------------------- package.json | 6 +- 2 files changed, 343 insertions(+), 433 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5eda45ce6..f5038d672 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,7 +35,7 @@ "http-proxy-middleware": "^3.0.3", "hyper-json": "~1.4.0", "jquery": "3.6.0", - "json.sortify": "~2.1.0", + "json.sortify": "github:cryptpad/JSON.sortify", "jsonwebtoken": "^9.0.0", "jszip": "3.10.1", "localforage": "^1.5.2", @@ -64,8 +64,8 @@ "x2js": "^3.4.4" }, "devDependencies": { - "eslint": "^8.57.0", - "eslint-plugin-compat": "^4.2.0", + "eslint": "^9.16.0", + "eslint-plugin-compat": "^6.0.1", "stylelint": "^16.9.0", "stylelint-config-standard-less": "^3.0.1" }, @@ -303,24 +303,70 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, + "node_modules/@eslint/config-array": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.0.tgz", + "integrity": "sha512-zdHg2FPIFNKPdcHWtiNT+jEFCHYVplAXRDlQDyqy0zGx/q2parwh7brGJSiTxRk/TSMkbM//zt/f5CHgyTyaSQ==", + "dev": true, + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@eslint/config-array/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/@eslint/core": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.0.tgz", + "integrity": "sha512-7ATR9F0e4W85D/0w7cU0SNj7qkAexMG+bAHEZOjo9akvGuhHE2m7umzWzfnpa0XAg5Kxc1BWmtPMV67jJ+9VUg==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", + "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", + "espree": "^10.0.1", + "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -328,25 +374,19 @@ "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, - "node_modules/@eslint/eslintrc/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, "node_modules/@eslint/eslintrc/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -357,106 +397,76 @@ } } }, - "node_modules/@eslint/eslintrc/node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/eslintrc/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/@eslint/eslintrc/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "node_modules/@eslint/eslintrc/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@eslint/eslintrc/node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "version": "9.16.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.16.0.tgz", + "integrity": "sha512-tw2HxzQkrbeuvyj1tG2Yqq+0H9wGoI2IMk4EOsQeX+vmd75FtJAzf+gTA69WF+baUKRYQ3x2kbLE08js5OsTVg==", "dev": true, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.3.tgz", + "integrity": "sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" + "levn": "^0.4.1" }, "engines": { - "node": ">=10.10.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@humanwhocodes/config-array/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", "dev": true, "dependencies": { - "ms": "2.1.2" + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">=18.18.0" } }, - "node_modules/@humanwhocodes/config-array/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", @@ -471,11 +481,18 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", - "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", - "dev": true + "node_modules/@humanwhocodes/retry": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz", + "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, "node_modules/@mcrowe/minibloom": { "version": "0.2.0", @@ -483,9 +500,9 @@ "integrity": "sha512-hce9MTbEkVIutibAkXAQddXCU9gMP/3OfcRaNo2V0v485iEzBRlniJG0ZTKumL8RbUA/fhpIGvrURiEZc+Crrg==" }, "node_modules/@mdn/browser-compat-data": { - "version": "5.5.12", - "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-5.5.12.tgz", - "integrity": "sha512-/AHFqy6OeNHS2NNZGFVRgQh+pnW8iAoV3d1fiO9b2PuQ3HzZpC30MrMrHtq1uOGy1/zcK4uPQEyI31jkM0NNAA==", + "version": "5.6.21", + "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-5.6.21.tgz", + "integrity": "sha512-yFGyNC6llnRbCELh1vH5mhrdSkQCrBs+wOyFjcYa3E9K3qzz6aDKnUSlDfWx+7pMeVr/iSKIdl1P60g2Jxs5sg==", "dev": true }, "node_modules/@node-saml/node-saml": { @@ -590,6 +607,12 @@ "@types/ms": "*" } }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true + }, "node_modules/@types/express": { "version": "4.17.20", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.20.tgz", @@ -625,6 +648,12 @@ "@types/node": "*" } }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, "node_modules/@types/mime": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.3.tgz", @@ -705,12 +734,6 @@ "@types/node": "*" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, "node_modules/@xmldom/xmldom": { "version": "0.8.10", "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz", @@ -1133,6 +1156,12 @@ "node": ">=0.10.0" } }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "node_modules/arr-flatten": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", @@ -1294,9 +1323,9 @@ } }, "node_modules/browserslist": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", - "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "version": "4.24.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", + "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", "dev": true, "funding": [ { @@ -1313,10 +1342,10 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001587", - "electron-to-chromium": "^1.4.668", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.13" + "caniuse-lite": "^1.0.30001669", + "electron-to-chromium": "^1.5.41", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.1" }, "bin": { "browserslist": "cli.js" @@ -1357,9 +1386,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001660", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001660.tgz", - "integrity": "sha512-GacvNTTuATm26qC74pt+ad1fW15mlQ/zuTzzY1ZoIzECTP8HURDfF43kNxPgf7H1jmelCBQTTbBNxdSXOA7Bqg==", + "version": "1.0.30001686", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001686.tgz", + "integrity": "sha512-Y7deg0Aergpa24M3qLC5xjNklnKnhsmSyR/V89dLZ1n0ucJIFNs7PgR2Yfa/Zf6W79SbBicgtGxZr2juHkEUIA==", "dev": true, "funding": [ { @@ -1405,6 +1434,14 @@ "json.sortify": "~2.1.0" } }, + "node_modules/chainpad-listmap/node_modules/json.sortify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/json.sortify/-/json.sortify-2.1.0.tgz", + "integrity": "sha512-otSldRQcu9PaQJJDeB1qGZUIoL7C4nxZunUVHieWPUMJvvVxIUhsMQUhR+r4OUZBwA1McnbS7sqDf5dYHzJsbw==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/chainpad-netflux": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/chainpad-netflux/-/chainpad-netflux-1.2.0.tgz", @@ -1418,15 +1455,6 @@ "resolved": "https://registry.npmjs.org/chainpad-server/-/chainpad-server-5.2.4.tgz", "integrity": "sha512-f4eErhcmIE67vfN9Dkfh0hX/IZDWERmfjdcfPEesXIHKu441jA84H0autvTAFsMTSPimlil7eeGnx4GLBVrR5Q==" }, - "node_modules/chainpad/node_modules/json.sortify": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/json.sortify/-/json.sortify-2.2.2.tgz", - "integrity": "sha512-wwFLdDffs747s5cqLA3htIKp9wdID2rWNofJKxwDjFo+rqqt5Vg7SnYOh7mc7MW6Iw43rrOFhr6MKytOtNceSA==", - "engines": { - "node": ">=4.0.0", - "npm": "~1.0.20" - } - }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -1615,9 +1643,9 @@ "integrity": "sha512-IlChnVUGG5T3w2gRZIaQgBtlvyuYnlUWs2YZIXXR3H9KrlO1PtBT3j+ykxvy9eZIWhk+V5SpBmhCQz5UXKrEKQ==" }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "dependencies": { "path-key": "^3.1.0", @@ -1768,18 +1796,6 @@ "defined": "^1.0.0" } }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/dragula": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/dragula/-/dragula-3.7.2.tgz", @@ -1807,9 +1823,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.687", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.687.tgz", - "integrity": "sha512-Ic85cOuXSP6h7KM0AIJ2hpJ98Bo4hyTUjc4yjMbkvD+8yTxEhfK9+8exT2KKYsSjnCn2tGsKVSZwE7ZgTORQCw==", + "version": "1.5.68", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.68.tgz", + "integrity": "sha512-FgMdJlma0OzUYlbrtZ4AeXjKxKPk6KT8WOP8BjcqxWtlg8qyJQjRzPJzUtUn5GBg1oQ26hFs7HOOHJMYiJRnvQ==", "dev": true }, "node_modules/emoji-regex": { @@ -1872,9 +1888,9 @@ } }, "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, "engines": { "node": ">=6" @@ -1898,92 +1914,109 @@ } }, "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "version": "9.16.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.16.0.tgz", + "integrity": "sha512-whp8mSQI4C8VXd+fLgSM0lh3UlmcFtVwUQjyKCFfsp+2ItAIYhlq/hqGahGqHE6cv9unM41VlqKk2VtKYR2TaA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.19.0", + "@eslint/core": "^0.9.0", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "9.16.0", + "@eslint/plugin-kit": "^0.2.3", + "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", + "@humanwhocodes/retry": "^0.4.1", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", + "cross-spawn": "^7.0.5", "debug": "^4.3.2", - "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, "node_modules/eslint-plugin-compat": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-compat/-/eslint-plugin-compat-4.2.0.tgz", - "integrity": "sha512-RDKSYD0maWy5r7zb5cWQS+uSPc26mgOzdORJ8hxILmWM7S/Ncwky7BcAtXVY5iRbKjBdHsWU8Yg7hfoZjtkv7w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-compat/-/eslint-plugin-compat-6.0.1.tgz", + "integrity": "sha512-0MeIEuoy8kWkOhW38kK8hU4vkb6l/VvyjpuYDymYOXmUY9NvTgyErF16lYuX+HPS5hkmym7lfA+XpYZiWYWmYA==", "dev": true, "dependencies": { - "@mdn/browser-compat-data": "^5.3.13", + "@mdn/browser-compat-data": "^5.5.35", "ast-metadata-inferer": "^0.8.0", - "browserslist": "^4.21.10", - "caniuse-lite": "^1.0.30001524", + "browserslist": "^4.23.1", + "caniuse-lite": "^1.0.30001639", "find-up": "^5.0.0", + "globals": "^15.7.0", "lodash.memoize": "^4.1.2", - "semver": "^7.5.4" + "semver": "^7.6.2" }, "engines": { - "node": ">=14.x" + "node": ">=18.x" }, "peerDependencies": { - "eslint": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-compat/node_modules/globals": { + "version": "15.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.13.0.tgz", + "integrity": "sha512-49TewVEz0UxZjr1WYYsWpPrhyC/B/pA8Bq0fUmet2n+eR7yn0IvNzNaoBwnK6mdkzcN+se7Ez9zUgULTz2QH4g==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", + "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -2001,21 +2034,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, "node_modules/eslint/node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -2033,6 +2051,18 @@ } } }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/eslint/node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -2045,57 +2075,33 @@ "node": ">=10.13.0" } }, - "node_modules/eslint/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/eslint/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node_modules/eslint/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", "dev": true, "dependencies": { - "acorn": "^8.9.0", + "acorn": "^8.14.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "eslint-visitor-keys": "^4.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/espree/node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -2113,6 +2119,18 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/esprima": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", @@ -2282,15 +2300,15 @@ } }, "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "dependencies": { - "flat-cache": "^3.0.4" + "flat-cache": "^4.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16.0.0" } }, "node_modules/file-saver": { @@ -2351,17 +2369,16 @@ } }, "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "dependencies": { "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" + "keyv": "^4.5.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16" } }, "node_modules/flatted": { @@ -2437,12 +2454,6 @@ "node": ">=6 <7 || >=8" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -2486,26 +2497,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", @@ -2566,15 +2557,12 @@ } }, "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -2629,12 +2617,6 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -2815,6 +2797,22 @@ "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -2824,16 +2822,6 @@ "node": ">=0.8.19" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, "node_modules/info-symbol": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/info-symbol/-/info-symbol-0.1.0.tgz", @@ -2949,15 +2937,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -3015,6 +2994,18 @@ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -3040,11 +3031,12 @@ "dev": true }, "node_modules/json.sortify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/json.sortify/-/json.sortify-2.1.0.tgz", - "integrity": "sha512-otSldRQcu9PaQJJDeB1qGZUIoL7C4nxZunUVHieWPUMJvvVxIUhsMQUhR+r4OUZBwA1McnbS7sqDf5dYHzJsbw==", + "version": "2.2.2", + "resolved": "git+ssh://git@github.com/cryptpad/JSON.sortify.git#0a96f91c3f3b127c3040bbc2d3eb6ae803cb2dfd", + "license": "Apache-2.0", "engines": { - "node": ">=0.10.0" + "node": ">=4.0.0", + "npm": ">=1.0.20" } }, "node_modules/jsonfile": { @@ -3605,9 +3597,9 @@ "integrity": "sha512-8oQOyEyh0MCnifNIfyvkNXpEELlVRzDleRivRgsDGh+5ZDG109axweVZ0RIOIpkQmTZk4/xVsBk/oLXpMSWEOw==" }, "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", "dev": true }, "node_modules/normalize-path": { @@ -3725,15 +3717,6 @@ "node": ">= 0.8" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, "node_modules/open-sans-fontface": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/open-sans-fontface/-/open-sans-fontface-1.4.0.tgz", @@ -3852,15 +3835,6 @@ "node": ">=8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -4392,6 +4366,15 @@ "resolved": "https://registry.npmjs.org/resolve/-/resolve-0.6.3.tgz", "integrity": "sha512-UHBY3viPlJKf85YijDUcikKX6tmF4SokIDp518ZDVT92JNDcG5uKIthaT/owt3Sar0lwtOafsQuwrg22/v2Dwg==" }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -4402,21 +4385,6 @@ "node": ">=0.10.0" } }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -4480,12 +4448,9 @@ "integrity": "sha512-BtT7+xPLdoeXsh6wOblaq6sRy/AsffFXgcwBNGtQJXeNgm9UD3HM3nWEmAERjdCNfE6jWglAtRbAPZ7rc2WtsQ==" }, "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dependencies": { - "lru-cache": "^6.0.0" - }, + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "bin": { "semver": "bin/semver.js" }, @@ -4787,6 +4752,18 @@ "node": ">=0.10.0" } }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/stylelint": { "version": "16.9.0", "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.9.0.tgz", @@ -4961,12 +4938,6 @@ "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/stylelint/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, "node_modules/stylelint/node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -5098,31 +5069,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/stylelint/node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/stylelint/node_modules/import-fresh/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/stylelint/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -5141,18 +5087,6 @@ "node": ">=0.10.0" } }, - "node_modules/stylelint/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/stylelint/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -5399,12 +5333,6 @@ "utrie": "^1.0.2" } }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, "node_modules/thirty-two": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/thirty-two/-/thirty-two-1.0.2.tgz", @@ -5508,18 +5436,6 @@ "node": ">= 0.8.0" } }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -5562,9 +5478,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", "dev": true, "funding": [ { @@ -5581,8 +5497,8 @@ } ], "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.2.0", + "picocolors": "^1.1.0" }, "bin": { "update-browserslist-db": "cli.js" @@ -5697,12 +5613,6 @@ "node": ">=0.4.0" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, "node_modules/write-file-atomic": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", diff --git a/package.json b/package.json index 1432c3c16..f236c225a 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "http-proxy-middleware": "^3.0.3", "hyper-json": "~1.4.0", "jquery": "3.6.0", - "json.sortify": "~2.1.0", + "json.sortify": "github:cryptpad/JSON.sortify", "jsonwebtoken": "^9.0.0", "jszip": "3.10.1", "localforage": "^1.5.2", @@ -67,8 +67,8 @@ "x2js": "^3.4.4" }, "devDependencies": { - "eslint": "^8.57.0", - "eslint-plugin-compat": "^4.2.0", + "eslint": "^9.16.0", + "eslint-plugin-compat": "^6.0.1", "stylelint": "^16.9.0", "stylelint-config-standard-less": "^3.0.1" }, From e1b61e437eb34681d3852a2156760fdbb7ccea47 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 4 Dec 2024 13:43:06 +0100 Subject: [PATCH 48/49] Use new eslint config format (v9) --- .eslintignore | 43 ---------------- .eslintrc.js | 58 ---------------------- eslint.config.js | 92 +++++++++++++++++++++++++++++++++++ www/common/cryptpad-common.js | 2 +- 4 files changed, 93 insertions(+), 102 deletions(-) delete mode 100644 .eslintignore delete mode 100644 .eslintrc.js create mode 100644 eslint.config.js diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index bcd65baeb..000000000 --- a/.eslintignore +++ /dev/null @@ -1,43 +0,0 @@ -# SPDX-FileCopyrightText: 2023 XWiki CryptPad Team and contributors -# -# SPDX-License-Identifier: AGPL-3.0-or-later - -node_modules/ -www/components/ -www/bower_components/ -www/common/onlyoffice/dist -www/common/onlyoffice/x2t -onlyoffice-dist/ - -www/scratch -www/accounts -www/lib -www/accounts -www/worker -www/todo - -*worker.bundle.js -_build - -#lib/plugins/ - -www/common/hyperscript.js - -www/pad/wysiwygarea-plugin.js -www/pad/mediatag-plugin.js -www/pad/mediatag-plugin-dialog.js -www/pad/disable-base64.js -www/pad/wordcount/ - -www/kanban/jkanban.js -www/common/jscolor.js - -www/common/media-tag-nacl.min.js - -customize/ - -www/debug/chainpad.dist.js - -www/pad/mathjax/ -www/code/mermaid*.js -www/code/orgmode.js diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 924eddfc3..000000000 --- a/.eslintrc.js +++ /dev/null @@ -1,58 +0,0 @@ -// SPDX-FileCopyrightText: 2024 XWiki CryptPad Team and contributors -// -// SPDX-License-Identifier: AGPL-3.0-or-later - -module.exports = { - 'env': { - 'browser': true, - 'es2021': true, - 'node': true - }, - 'plugins': ['compat'], - 'extends': ['eslint:recommended', 'plugin:compat/recommended'], - "globals": { - "define": "readonly", - }, - 'overrides': [ - { - 'env': { - 'node': true - }, - 'files': [ - '.eslintrc.{js,cjs}' - ], - 'parserOptions': { - 'sourceType': 'script' - } - } - ], - 'parserOptions': { - 'ecmaVersion': 'latest' - }, - 'rules': { - 'indent': [ - 'off', // TODO enable this check - 4 - ], - 'linebreak-style': [ - 'off', // git handles linebreak conversion for us - 'unix' - ], - 'quotes': [ - 'off', // TODO enable this check - 'single' - ], - 'semi': [ - 'error', - 'always' - ], - - // TODO remove these exceptions from the eslint defaults - 'no-irregular-whitespace': ['off'], - 'no-self-assign': ['off'], - 'no-empty': ['off'], - 'no-useless-escape': ['off'], - 'no-extra-boolean-cast': ['off'], - 'no-prototype-builtins': ['off'], - } -}; diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 000000000..6402b0866 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,92 @@ +// SPDX-FileCopyrightText: 2024 XWiki CryptPad Team and contributors +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +const compatPlugin = require("eslint-plugin-compat"); +const globals = require("globals"); +const js = require("@eslint/js"); +const FlatCompat = require("@eslint/eslintrc").FlatCompat; + +const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, + allConfig: js.configs.all +}); + +module.exports = [{ + ignores: [ + "**/node_modules/", + "www/components/", + "www/bower_components/", + "www/common/onlyoffice/dist", + "www/common/onlyoffice/x2t", + "**/onlyoffice-dist/", + "www/scratch", + "www/accounts", + "www/lib", + "www/accounts", + "www/worker", + "www/todo", + "**/*worker.bundle.js", + "**/_build", + "www/common/hyperscript.js", + "www/pad/wysiwygarea-plugin.js", + "www/pad/mediatag-plugin.js", + "www/pad/mediatag-plugin-dialog.js", + "www/pad/disable-base64.js", + "www/pad/wordcount/", + "www/kanban/jkanban.js", + "www/common/jscolor.js", + "www/common/media-tag-nacl.min.js", + "**/customize/", + "www/debug/chainpad.dist.js", + "www/pad/mathjax/", + "www/code/mermaid*.js", + "www/code/orgmode.js", + ], +}, ...compat.extends("eslint:recommended", "plugin:compat/recommended"), { + plugins: { + compatPlugin, + }, + + languageOptions: { + globals: { + ...globals.browser, + ...globals.node, + define: "readonly", + }, + + ecmaVersion: "latest", + sourceType: "commonjs", + }, + + rules: { + indent: ["off", 4], + "linebreak-style": ["off", "unix"], + quotes: ["off", "single"], + semi: ["error", "always"], + "no-irregular-whitespace": ["off"], + "no-self-assign": ["off"], + "no-empty": ["off"], + "no-useless-escape": ["off"], + "no-extra-boolean-cast": ["off"], + "no-prototype-builtins": ["off"], + "no-unused-vars": [ + "error", + { + caughtErrors: "none" + } + ] + }, +}, { + files: ["**/.eslintrc.{js,cjs}"], + + languageOptions: { + globals: { + ...globals.node, + }, + + ecmaVersion: 5, + sourceType: "commonjs", + }, +}]; diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index e2d6a3746..ada56e9be 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -2713,7 +2713,7 @@ define([ window.addEventListener('unload', function () { postMsg('CLOSE'); }); - // eslint-disable-next-line no-constant-condition + // eslint-disable-next-line no-constant-condition,no-constant-binary-expression } else if (false && !noWorker && !noSharedWorker && 'serviceWorker' in navigator) { var initializing = true; var stopWaiting = waitFor2(); // Call this function when we're ready From b969a68d78bbb84a459eae9a22b20169fda00fd2 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 4 Dec 2024 13:49:23 +0100 Subject: [PATCH 49/49] lint compliance --- eslint.config.js | 1 + www/admin/inner.js | 19 +++++++++++-------- www/common/toolbar.js | 2 +- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/eslint.config.js b/eslint.config.js index 6402b0866..eba722d94 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -71,6 +71,7 @@ module.exports = [{ "no-useless-escape": ["off"], "no-extra-boolean-cast": ["off"], "no-prototype-builtins": ["off"], + "no-use-before-define": ["error"], "no-unused-vars": [ "error", { diff --git a/www/admin/inner.js b/www/admin/inner.js index c8342a6f7..9153436e5 100644 --- a/www/admin/inner.js +++ b/www/admin/inner.js @@ -968,12 +968,7 @@ define([ }); }; - let btn = blocks.activeButton('primary', '', - Messages.admin_colorChange, (done) => { - let color = $input.val(); - setColor(color, done); - }); - + let $input = $(); let onColorPicked = () => { require(['/lib/less.min.js'], (Less) => { let color = $input.val(); @@ -995,7 +990,14 @@ define([ $preview.find('.cp-admin-color-preview-light a').attr('style', `color: ${color} !important`); }); }; - let $input = $(input).on('change', onColorPicked).addClass('cp-admin-color-picker'); + $input = $(input).on('change', onColorPicked).addClass('cp-admin-color-picker'); + + let btn = blocks.activeButton('primary', '', + Messages.admin_colorChange, (done) => { + let color = $input.val(); + setColor(color, done); + }); + UI.confirmButton($remove, { classes: 'btn-danger', @@ -3185,6 +3187,7 @@ define([ labelEnd, ], blocks.nav([button])); + let send = function () {}; var refresh = getApi(function (Broadcast) { $active.empty(); var removeButton = blocks.button('danger', '', Messages.admin_maintenanceCancel); @@ -3246,7 +3249,7 @@ define([ }; }; - var send = function (data) { + send = function (data) { disable($button); sFrameChan.query('Q_ADMIN_RPC', { cmd: 'ADMIN_DECREE', diff --git a/www/common/toolbar.js b/www/common/toolbar.js index 2b0d2f648..e950b3981 100644 --- a/www/common/toolbar.js +++ b/www/common/toolbar.js @@ -1416,7 +1416,7 @@ MessengerUI, Messages, Pages, PadTypes) { tb['pad'] = function () { toolbar.$file.show(); - addElement([ + toolbar.addElement([ 'chat', 'collapse', 'userlist', 'title', 'useradmin', 'spinner',