upstream: integrar Oasis 1.3.1
Base del merge a tres bandas: git 0.9.5 de epsylon, esta rama y el src de la
APK oficial 1.3.1 (la variante movil: OASIS_MOBILE, regex sin \p{}, audio y
video de Android). Corre en el mismo nodejs-mobile 18.20.4 que ya usabamos.
Se conserva de la rama: Karvan, identidades y multicuenta, topbar y barra
inferior, borrado de EXIF sin sharp, filtro hot del foro, RTC sin STUN y los
modulos apagados en movil (wallet, banking, torrents).
Se toma de upstream lo que ya hace de serie: respuesta citada en chats, ssb-lan
en movil, configuracion en ~/.ssb/oasis (sobrevive a reinstalar el backend).
El asistente de bienvenida deja elegir workflow tambien en movil.
This commit is contained in:
parent
8d838dd8b1
commit
c332afd6ea
265 changed files with 80970 additions and 29167 deletions
|
|
@ -1,17 +1,27 @@
|
|||
const { form, button, div, h2, h3, p, section, select, option, input, br, a, label, span, img } = require("../server/node_modules/hyperaxe");
|
||||
const { form, button, div, h2, h3, p, section, select, option, input, br, a, label, span, img, strong, table, tr, td, ul, li } = require("../server/node_modules/hyperaxe");
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { getConfig } = require('../configs/config-manager.js');
|
||||
const { template, selectedLanguage, i18n, setLanguage } = require('./main_views');
|
||||
const { template, selectedLanguage, i18n, setLanguage, INBOX_BOT_ORDER, inboxBotLabel, THEMES } = require('./main_views');
|
||||
const i18nBase = require("../client/assets/translations/i18n");
|
||||
const { WORKFLOWS, currentWorkflow } = require('../models/workflows_model');
|
||||
const html = require("../server/node_modules/hyperaxe");
|
||||
// selector de identidades: la implementacion vive en ./identities_view.js
|
||||
const { renderIdentities } = require('./identities_view')({ i18n, html });
|
||||
const { renderVerificationReport, renderRebuildReport } = require('./backup_view');
|
||||
|
||||
const snhUrl = "https://wiki.solarnethub.com/socialnet/overview";
|
||||
const BLOB_CACHE_OPTIONS = [512, 1024, 2048, 5120, 10240, 0];
|
||||
const sizeLabel = (bytes) => {
|
||||
let value = Number(bytes) || 0;
|
||||
const units = ['B', 'KB', 'MB', 'GB'];
|
||||
let unit = 0;
|
||||
while (value >= 1024 && unit < units.length - 1) { value /= 1024; unit += 1; }
|
||||
return `${unit === 0 ? Math.round(value) : value.toFixed(1)} ${units[unit]}`;
|
||||
};
|
||||
const blobCacheOptionLabel = (mb) => mb === 0 ? i18n.settingsBlobCacheUnlimited : (mb >= 1024 ? `${mb / 1024} GB` : `${mb} MB`);
|
||||
|
||||
const themeFilePath = path.join(__dirname, '../configs/oasis-config.json');
|
||||
const themeFilePath = require('../configs/config-manager').configFilePath;
|
||||
const getThemeConfig = () => {
|
||||
try {
|
||||
const configData = fs.readFileSync(themeFilePath);
|
||||
|
|
@ -22,31 +32,28 @@ const getThemeConfig = () => {
|
|||
}
|
||||
};
|
||||
|
||||
const settingsView = ({ version, aiPrompt, fediverseAccount, fediverseError }) => {
|
||||
const settingsView = (params) => {
|
||||
const { version, aiPrompt, aiExportCount = 0, blobCache = null, fediverseAccount, telegramAccount = null, telegramLogin = null, peertubeAccount = null, nextcloudAccount = null, verification = null, rebuild = null } = params;
|
||||
const currentThemeConfig = getThemeConfig();
|
||||
const theme = currentThemeConfig.themes?.current || "Dark-SNH";
|
||||
const currentConfig = getConfig();
|
||||
let serverConfig = {};
|
||||
try { serverConfig = JSON.parse(fs.readFileSync(path.join(__dirname, '../configs/server-config.json'), 'utf8')); } catch (_) {}
|
||||
try { serverConfig = require('../configs/config-manager.js').readServerConfig(); } catch (_) {}
|
||||
const currentHops = (serverConfig.friends && Number.isFinite(serverConfig.friends.hops)) ? serverConfig.friends.hops : 2;
|
||||
const walletUrl = currentConfig.wallet.url;
|
||||
const walletUser = currentConfig.wallet.user;
|
||||
const walletFee = currentConfig.wallet.fee;
|
||||
const currentWish = currentConfig.wish === 'mutuals' ? 'mutuals' : 'whole';
|
||||
const currentWish = ['mutuals', 'only-lan', 'local'].includes(currentConfig.wish) ? currentConfig.wish : 'whole';
|
||||
const currentPmVisibility = currentConfig.pmVisibility === 'mutuals' ? 'mutuals' : 'whole';
|
||||
const currentPhone = currentConfig.phone && typeof currentConfig.phone === 'object' ? currentConfig.phone : {};
|
||||
|
||||
const themeElements = [
|
||||
option({ value: "Dark-SNH", ...(theme === "Dark-SNH" ? true : undefined ? { selected: true } : {})}, "Dark-SNH"),
|
||||
option({ value: "Clear-SNH", ...(theme === "Clear-SNH" ? true : undefined ? { selected: true } : {})}, "Clear-SNH"),
|
||||
option({ value: "Purple-SNH", ...(theme === "Purple-SNH" ? true : undefined ? { selected: true } : {})}, "Purple-SNH"),
|
||||
option({ value: "Matrix-SNH", ...(theme === "Matrix-SNH" ? true : undefined ? { selected: true } : {})}, "Matrix-SNH"),
|
||||
option({ value: "OasisMobile", ...(theme === "OasisMobile" ? true : undefined ? { selected: true } : {})}, "Oasis-Mobile")
|
||||
];
|
||||
const themeElements = THEMES.map(([value, name]) => option({ value, ...(theme === value ? { selected: true } : {}) }, name));
|
||||
|
||||
const activeWorkflow = currentWorkflow(currentConfig) || '';
|
||||
const modOn = (name) => (currentConfig.modules || {})[`${name}Mod`] === 'on';
|
||||
const isMobile = process.env.OASIS_MOBILE === '1';
|
||||
|
||||
const workflowSection = section(
|
||||
const workflowSection = section({ id: "workflows" },
|
||||
div({ class: "tags-header" },
|
||||
h2(i18n.workflowsTitle),
|
||||
p(i18n.workflowsDescription),
|
||||
|
|
@ -74,26 +81,45 @@ const settingsView = ({ version, aiPrompt, fediverseAccount, fediverseError }) =
|
|||
button({ type: "submit" }, i18n.rebuildName)
|
||||
);
|
||||
|
||||
const updateFlagPath = path.join(__dirname, '../server/.update_required');
|
||||
let updateButton = null;
|
||||
if (fs.existsSync(updateFlagPath)) {
|
||||
updateButton = form(
|
||||
{ action: "/update", method: "post" },
|
||||
button({ type: "submit" }, i18n.updateit)
|
||||
const updateInfo = (() => { try { return require('../backend/updater').readUpdateInfo(); } catch (_) { return null; } })();
|
||||
let updatePanel = null;
|
||||
if (updateInfo) {
|
||||
const d = updateInfo.details || {};
|
||||
const day = (iso) => String(iso || '').slice(0, 10);
|
||||
const versionLine = (v, c) => `${v || '?'}${c ? ` · ${c.hash} · ${day(c.date)}` : ''}`;
|
||||
const row = (name, ...value) => tr(td({ class: "tribe-info-label" }, name), td({ class: "tribe-info-value" }, ...value));
|
||||
updatePanel = section({ id: "update" },
|
||||
div({ class: "torrent-download update-panel" },
|
||||
div({ class: "torrent-oasis torrent-detail-section" },
|
||||
h3({ class: "torrent-section-title" }, i18n.notifyUpdateLabel),
|
||||
table({ class: "tribe-info-table torrent-file-info" },
|
||||
row(i18n.updateInstalledLabel, versionLine(updateInfo.installedVersion, d.installed)),
|
||||
row(i18n.updateAvailableLabel, versionLine(updateInfo.version, d.available)),
|
||||
Array.isArray(d.commits) && d.commits.length
|
||||
? row(i18n.updateChangesLabel, ul({ class: "update-changes" },
|
||||
...d.commits.map(c => li(`${day(c.date)} · ${c.subject}`)),
|
||||
d.count > d.commits.length ? li(`+${d.count - d.commits.length}`) : null))
|
||||
: null,
|
||||
d.files ? row(i18n.updateFilesLabel, `${d.files} · +${d.insertions} −${d.deletions}`) : null,
|
||||
d.origin ? row(i18n.updateOriginLabel, span({ class: "bank-address-code" }, d.origin)) : null
|
||||
),
|
||||
isMobile
|
||||
? ((updateInfo.apk || updateInfo.page)
|
||||
? a({ href: updateInfo.apk || updateInfo.page, class: "filter-btn update-download-link" }, `\u2B07 OASIS${updateInfo.version ? ` ${updateInfo.version}` : ''}`)
|
||||
: null)
|
||||
: form({ action: "/update", method: "post" },
|
||||
button({ type: "submit", class: "filter-btn" }, `\u2B07 OASIS${updateInfo.version ? ` ${updateInfo.version}` : ''}`)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return template(
|
||||
i18n.settings,
|
||||
section(
|
||||
div({ class: "tags-header" },
|
||||
h2(i18n.settings),
|
||||
p(a({ href: snhUrl, target: "_blank" }, i18n.settingsIntro({ version }))),
|
||||
updateButton
|
||||
)
|
||||
),
|
||||
const filter = params.filter === 'multiverse' && modOn('fediverse') ? 'multiverse' : 'oasis';
|
||||
const oasisParts = [
|
||||
updatePanel,
|
||||
renderIdentities(require('../server/ssb_config').account),
|
||||
section(
|
||||
section({ id: "language" },
|
||||
div({ class: "tags-header" },
|
||||
h2(i18n.language),
|
||||
p(i18n.languageDescription),
|
||||
|
|
@ -104,6 +130,8 @@ const settingsView = ({ version, aiPrompt, fediverseAccount, fediverseError }) =
|
|||
languageOption("Español", "es"),
|
||||
languageOption("Français", "fr"),
|
||||
languageOption("Euskara", "eu"),
|
||||
languageOption("Català", "ca"),
|
||||
languageOption("Galego", "gl"),
|
||||
languageOption("Deutsch", "de"),
|
||||
languageOption("Italiano", "it"),
|
||||
languageOption("Português", "pt"),
|
||||
|
|
@ -118,7 +146,7 @@ const settingsView = ({ version, aiPrompt, fediverseAccount, fediverseError }) =
|
|||
)
|
||||
)
|
||||
),
|
||||
section(
|
||||
section({ id: "ux" },
|
||||
div({ class: "tags-header" },
|
||||
h2(i18n.uxModeTitle || "UX"),
|
||||
p(i18n.uxModeDescription || "Select which UX navigation mode you want for your GUI."),
|
||||
|
|
@ -127,7 +155,8 @@ const settingsView = ({ version, aiPrompt, fediverseAccount, fediverseError }) =
|
|||
(() => {
|
||||
const aiNavEnabled = currentConfig.modules && currentConfig.modules.aiNavMod === 'on';
|
||||
const chatsEnabled = currentConfig.modules && currentConfig.modules.chatsMod === 'on';
|
||||
const cur = currentConfig.ux?.current === "ainav" ? "ainav" : currentConfig.ux?.current === "chats" ? "chats" : "blocks";
|
||||
const phoneEnabled = !!(currentConfig.modules && currentConfig.modules.phoneMod !== 'off');
|
||||
const cur = currentConfig.ux?.current === "ainav" ? "ainav" : currentConfig.ux?.current === "chats" ? "chats" : currentConfig.ux?.current === "feed" ? "feed" : currentConfig.ux?.current === "phone" ? "phone" : "blocks";
|
||||
const uxCard = (value, title, image) => label({ class: "welcome-ux-option" },
|
||||
input({ type: "radio", name: "ux", value, ...(cur === value ? { checked: true } : {}) }),
|
||||
img({ src: image, class: "welcome-ux-shot", alt: title }),
|
||||
|
|
@ -135,16 +164,17 @@ const settingsView = ({ version, aiPrompt, fediverseAccount, fediverseError }) =
|
|||
);
|
||||
return div({ class: "welcome-ux-grid" },
|
||||
uxCard("blocks", i18n.uxModeMenus || "Blocks", "/assets/images/ux-blocks.png"),
|
||||
chatsEnabled ? uxCard("chats", i18n.chatsTitle || "Chats", "/assets/images/ux-chats.png") : null,
|
||||
aiNavEnabled ? uxCard("ainav", i18n.uxModeAINav || "AI", "/assets/images/ux-ainav.png") : null
|
||||
aiNavEnabled ? uxCard("ainav", i18n.uxModeAINav || "AI", "/assets/images/ux-ainav.png") : null,
|
||||
chatsEnabled ? uxCard("chats", i18n.uxModeChats || "Conversations", "/assets/images/ux-chats.png") : null,
|
||||
uxCard("feed", i18n.uxModeFeed || "Microblogging", "/assets/images/ux-feed.png"),
|
||||
phoneEnabled ? uxCard("phone", i18n.phoneTitle || "Phone", "/assets/images/ux-phone.png") : null
|
||||
);
|
||||
})(),
|
||||
button({ type: "submit" }, i18n.saveSettings)
|
||||
)
|
||||
)
|
||||
),
|
||||
workflowSection,
|
||||
section(
|
||||
section({ id: "theme" },
|
||||
div({ class: "tags-header" },
|
||||
h2(i18n.theme),
|
||||
p(i18n.themeIntro),
|
||||
|
|
@ -157,7 +187,24 @@ const settingsView = ({ version, aiPrompt, fediverseAccount, fediverseError }) =
|
|||
)
|
||||
)
|
||||
),
|
||||
section(
|
||||
section({ id: "wish" },
|
||||
div({ class: "tags-header" },
|
||||
h2(i18n.settingsWishTitle),
|
||||
p(i18n.settingsWishDesc),
|
||||
form(
|
||||
{ action: "/settings/wish", method: "POST" },
|
||||
select({ name: "wish" },
|
||||
option({ value: "whole", ...(currentWish === "whole" ? { selected: true } : {})}, i18n.settingsWishWhole),
|
||||
option({ value: "mutuals", ...(currentWish === "mutuals" ? { selected: true } : {})}, i18n.settingsWishMutuals),
|
||||
option({ value: "only-lan", ...(currentWish === "only-lan" ? { selected: true } : {})}, i18n.settingsWishOnlyLan || "Only LAN"),
|
||||
option({ value: "local", ...(currentWish === "local" ? { selected: true } : {})}, i18n.settingsWishLocal || "Local")
|
||||
), br(), br(),
|
||||
button({ type: "submit" }, i18n.saveSettings)
|
||||
)
|
||||
)
|
||||
),
|
||||
workflowSection,
|
||||
section({ id: "home-page" },
|
||||
div({ class: "tags-header" },
|
||||
h2(i18n.homePageTitle),
|
||||
p(i18n.homePageDescription),
|
||||
|
|
@ -185,7 +232,7 @@ const settingsView = ({ version, aiPrompt, fediverseAccount, fediverseError }) =
|
|||
)
|
||||
)
|
||||
),
|
||||
modOn('ai') ? section(
|
||||
modOn('ai') ? section({ id: "ai" },
|
||||
div({ class: "tags-header" },
|
||||
h2(i18n.aiTitle),
|
||||
p(i18n.aiSettingsDescription),
|
||||
|
|
@ -212,11 +259,12 @@ const settingsView = ({ version, aiPrompt, fediverseAccount, fediverseError }) =
|
|||
span({ class: "lan-checkbox-text" }, i18n.aiSuggestionsEnable)
|
||||
),
|
||||
br(),
|
||||
button({ type: "submit" }, i18n.saveSettings)
|
||||
button({ type: "submit" }, i18n.saveSettings),
|
||||
Number(aiExportCount) > 0 ? button({ type: "submit", formaction: "/ai/export", attrs: { formmethod: "GET" }, class: "ai-export-btn" }, `${i18n.aiExportFineTuning} (${aiExportCount})`) : null
|
||||
)
|
||||
)
|
||||
) : null,
|
||||
section(
|
||||
section({ id: "logstream" },
|
||||
div({ class: "tags-header" },
|
||||
h2(i18n.ssbLogStream),
|
||||
p(i18n.ssbLogStreamDescription),
|
||||
|
|
@ -234,7 +282,24 @@ const settingsView = ({ version, aiPrompt, fediverseAccount, fediverseError }) =
|
|||
)
|
||||
)
|
||||
),
|
||||
section(
|
||||
blobCache ? section({ id: "blobcache" },
|
||||
div({ class: "tags-header" },
|
||||
h2(i18n.settingsBlobCacheTitle),
|
||||
p(i18n.settingsBlobCacheDesc),
|
||||
blobCache.usage ? p({ class: "blob-cache-usage" }, strong(`${i18n.settingsBlobCacheUsage}: `), `${sizeLabel(blobCache.usage.bytes)} · ${blobCache.usage.count} ${i18n.settingsBlobCacheFiles}`) : null,
|
||||
blobCache.cleaned !== null ? p({ class: "blob-cache-notice" }, String(i18n.settingsBlobCacheCleaned).replace('{n}', String(blobCache.cleaned)).replace('{size}', sizeLabel(blobCache.freed))) : null,
|
||||
form(
|
||||
{ action: "/settings/blob-cache", method: "POST" },
|
||||
label({ for: "blob_cache_mb" }, i18n.settingsBlobCacheLimit),
|
||||
br(),
|
||||
select({ id: "blob_cache_mb", name: "blob_cache_mb" }, ...BLOB_CACHE_OPTIONS.map(mb => option({ value: String(mb), ...(mb === blobCache.maxMB ? { selected: true } : {}) }, blobCacheOptionLabel(mb)))),
|
||||
br(), br(),
|
||||
button({ type: "submit" }, i18n.saveSettings),
|
||||
blobCache.maxMB > 0 ? button({ type: "submit", formaction: "/settings/blob-cache/collect", class: "blob-cache-clean-btn" }, i18n.settingsBlobCacheCleanNow) : null
|
||||
)
|
||||
)
|
||||
) : null,
|
||||
section({ id: "replication" },
|
||||
div({ class: "tags-header" },
|
||||
h2(i18n.settingsReplicationTitle || 'Replication'),
|
||||
p(i18n.settingsReplicationDesc || 'Configure the number of hops your peer follows out from your own feed when replicating content.'),
|
||||
|
|
@ -255,7 +320,7 @@ const settingsView = ({ version, aiPrompt, fediverseAccount, fediverseError }) =
|
|||
)
|
||||
)
|
||||
),
|
||||
section(
|
||||
section({ id: "lan" },
|
||||
div({ class: "tags-header" },
|
||||
h2(i18n.settingsLanTitle || 'LAN Broadcasting'),
|
||||
p(i18n.settingsLanDesc || 'Periodically announce this peer to other Oasis instances on the same local network. Disable to stop UDP broadcasts.'),
|
||||
|
|
@ -277,98 +342,105 @@ const settingsView = ({ version, aiPrompt, fediverseAccount, fediverseError }) =
|
|||
)
|
||||
)
|
||||
),
|
||||
section(
|
||||
div({ class: "tags-header" },
|
||||
h2(i18n.settingsWishTitle),
|
||||
p(i18n.settingsWishDesc),
|
||||
form(
|
||||
{ action: "/settings/wish", method: "POST" },
|
||||
select({ name: "wish" },
|
||||
option({ value: "whole", ...(currentWish === "whole" ? true : undefined ? { selected: true } : {})}, i18n.settingsWishWhole),
|
||||
option({ value: "mutuals", ...(currentWish === "mutuals" ? true : undefined ? { selected: true } : {})}, i18n.settingsWishMutuals),
|
||||
option({ value: "only-lan", ...(currentWish === "only-lan" ? true : undefined ? { selected: true } : {})}, i18n.settingsWishOnlyLan || "Only LAN")
|
||||
), br(), br(),
|
||||
button({ type: "submit" }, i18n.saveSettings)
|
||||
)
|
||||
)
|
||||
),
|
||||
section(
|
||||
section({ id: "pm-visibility" },
|
||||
div({ class: "tags-header" },
|
||||
h2(i18n.settingsPmVisibilityTitle),
|
||||
p(i18n.settingsPmVisibilityDesc),
|
||||
form(
|
||||
{ action: "/settings/pm-visibility", method: "POST" },
|
||||
select({ name: "pmVisibility" },
|
||||
option({ value: "whole", ...(currentPmVisibility === "whole" ? true : undefined ? { selected: true } : {})}, i18n.settingsPmVisibilityWhole),
|
||||
option({ value: "mutuals", ...(currentPmVisibility === "mutuals" ? true : undefined ? { selected: true } : {})}, i18n.settingsPmVisibilityMutuals)
|
||||
option({ value: "whole", ...(currentPmVisibility === "whole" ? { selected: true } : {})}, i18n.settingsPmVisibilityWhole),
|
||||
option({ value: "mutuals", ...(currentPmVisibility === "mutuals" ? { selected: true } : {})}, i18n.settingsPmVisibilityMutuals)
|
||||
), br(), br(),
|
||||
button({ type: "submit" }, i18n.saveSettings)
|
||||
)
|
||||
)
|
||||
),
|
||||
modOn('phone') ? section({ id: "phone" },
|
||||
div({ class: "tags-header" },
|
||||
h2(i18n.phoneTitle),
|
||||
p(i18n.phoneSettingsDesc),
|
||||
form(
|
||||
{ action: "/settings/phone", method: "POST" },
|
||||
select({ name: "visibility" },
|
||||
option({ value: "whole", ...(!currentPhone.dnd && currentPhone.visibility !== "mutuals" ? { selected: true } : {})}, i18n.settingsPmVisibilityWhole),
|
||||
option({ value: "mutuals", ...(!currentPhone.dnd && currentPhone.visibility === "mutuals" ? { selected: true } : {})}, i18n.settingsPmVisibilityMutuals),
|
||||
option({ value: "dnd", ...(currentPhone.dnd ? { selected: true } : {})}, i18n.phoneDnd)
|
||||
), br(), br(),
|
||||
label(i18n.settingsPhoneVideo), br(),
|
||||
select({ name: "video" },
|
||||
option({ value: "on", ...(currentPhone.video !== false ? { selected: true } : {}) }, i18n.settingsPhoneVideoOn),
|
||||
option({ value: "off", ...(currentPhone.video === false ? { selected: true } : {}) }, i18n.settingsPhoneVideoOff)
|
||||
), br(), br(),
|
||||
button({ type: "submit" }, i18n.saveSettings)
|
||||
)
|
||||
)
|
||||
) : null,
|
||||
modOn('inbox') ? section({ id: "inbox-bots" },
|
||||
div({ class: "tags-header" },
|
||||
h2(i18n.settingsInboxBotsTitle),
|
||||
p(i18n.settingsInboxBotsDesc),
|
||||
form(
|
||||
{ action: "/settings/inbox-bots", method: "POST" },
|
||||
...INBOX_BOT_ORDER.map(bot =>
|
||||
label({ for: `inbox-bot-${bot}`, class: "lan-checkbox-label inbox-bot-label" },
|
||||
input({
|
||||
type: "checkbox",
|
||||
id: `inbox-bot-${bot}`,
|
||||
name: "bots",
|
||||
value: bot,
|
||||
class: "lan-checkbox-input",
|
||||
checked: (Array.isArray(currentConfig.inboxMutedBots) && currentConfig.inboxMutedBots.includes(bot)) ? undefined : true
|
||||
}),
|
||||
span({ class: "lan-checkbox-text" }, inboxBotLabel(bot))
|
||||
)
|
||||
),
|
||||
br(),
|
||||
button({ type: "submit" }, i18n.saveSettings)
|
||||
)
|
||||
)
|
||||
) : null,
|
||||
modOn('wallet') ? section(
|
||||
{ id: "wallet" },
|
||||
div({ class: "tags-header" },
|
||||
h2(i18n.wallet),
|
||||
p(
|
||||
i18n.walletSettingsDescription, " ",
|
||||
a({ href: "docs/ecoin.md", target: "_blank", rel: "noopener" }, `[${i18n.walletSettingsDocLink}]`)
|
||||
isMobile ? i18n.walletSettingsMobileDescription : i18n.walletSettingsDescription
|
||||
),
|
||||
isMobile ? a({ href: require('../backend/updater.js').ecoinWalletDownloadUrl(), class: "update-download-link" }, i18n.walletDownloadEcoin) : null,
|
||||
form(
|
||||
{ action: "/settings/wallet", method: "POST" },
|
||||
label({ for: "wallet_url" }, i18n.walletAddress), br(),
|
||||
input({ type: "text", id: "wallet_url", name: "wallet_url", placeholder: walletUrl, value: walletUrl }), br(),
|
||||
label({ for: "wallet_url" }, i18n.walletRpcUrl), br(),
|
||||
input({ type: "text", id: "wallet_url", name: "wallet_url", placeholder: "http://localhost:7474", value: walletUrl || "http://localhost:7474" }), br(),
|
||||
label({ for: "wallet_user" }, i18n.walletUser), br(),
|
||||
input({ type: "text", id: "wallet_user", name: "wallet_user", placeholder: walletUser, value: walletUser }), br(),
|
||||
input({ type: "text", id: "wallet_user", name: "wallet_user", placeholder: "ecoinrpc", value: walletUser }), br(),
|
||||
label({ for: "wallet_pass" }, i18n.walletPass), br(),
|
||||
input({ type: "password", id: "wallet_pass", name: "wallet_pass" }), br(),
|
||||
label({ for: "wallet_fee" }, i18n.walletFee), br(),
|
||||
input({ type: "text", id: "wallet_fee", name: "wallet_fee", placeholder: walletFee, value: walletFee }), br(),
|
||||
button({ type: "submit" }, i18n.walletConfiguration)
|
||||
input({ type: "text", id: "wallet_fee", name: "wallet_fee", placeholder: "5", value: walletFee || "5" }), br(),
|
||||
button({ type: "submit" }, i18n.walletConfiguration),
|
||||
walletUser ? " " : null,
|
||||
walletUser ? button({ type: "submit", class: "delete-btn", formaction: "/settings/wallet/disconnect", attrs: { formmethod: "POST" } }, i18n.walletDisconnectButton) : null
|
||||
)
|
||||
)
|
||||
) : null,
|
||||
modOn('fediverse') ? section(
|
||||
{ id: "multiverse" },
|
||||
section({ id: "verification" },
|
||||
div({ class: "tags-header" },
|
||||
h2(i18n.fediverseSettingsTitle),
|
||||
div({ class: "fediverse-network" },
|
||||
h3("Mastodon"),
|
||||
p(i18n.fediverseTokenHelp),
|
||||
fediverseError ? p({ class: "fediverse-error" }, i18n[fediverseError] || i18n.fediverseError) : "",
|
||||
fediverseAccount
|
||||
? (() => {
|
||||
const host = String(fediverseAccount.instance || "").replace(/^https?:\/\//, "");
|
||||
const profileUrl = `${fediverseAccount.instance}/@${fediverseAccount.acct}`;
|
||||
const link = (txt) => a({ href: profileUrl, target: "_blank", rel: "noopener noreferrer" }, txt);
|
||||
return form(
|
||||
{ action: "/settings/fediverse/disconnect", method: "POST" },
|
||||
p(
|
||||
`${i18n.fediverseConnectedAs}: `,
|
||||
link(`${fediverseAccount.acct}@${host}`)
|
||||
),
|
||||
button({ type: "submit" }, i18n.fediverseDisconnect)
|
||||
);
|
||||
})()
|
||||
: form(
|
||||
{ action: "/settings/fediverse", method: "POST" },
|
||||
label({ for: "fediverse_instance" }, i18n.fediverseInstanceLabel), br(),
|
||||
input({ type: "text", id: "fediverse_instance", name: "instance", placeholder: "mastodon.social", required: true }), br(),
|
||||
label({ for: "fediverse_token" }, i18n.fediverseTokenLabel), br(),
|
||||
input({ type: "password", id: "fediverse_token", name: "token", autocomplete: "off", required: true }), br(),
|
||||
button({ type: "submit" }, i18n.fediverseConnect)
|
||||
)
|
||||
)
|
||||
h2(i18n.verificationTitle),
|
||||
p(i18n.verificationDescription),
|
||||
form({ action: "/settings/verify", method: "post" }, button({ type: "submit" }, i18n.verificationRun)),
|
||||
verification && verification.error ? p({ class: "backup-check-bad" }, verification.error) : renderVerificationReport(verification)
|
||||
)
|
||||
) : null,
|
||||
section(
|
||||
),
|
||||
section({ id: "indexes" },
|
||||
div({ class: "tags-header" },
|
||||
h2(i18n.indexes),
|
||||
p(i18n.indexesDescription),
|
||||
rebuildButton
|
||||
rebuildButton,
|
||||
renderRebuildReport(rebuild)
|
||||
)
|
||||
),
|
||||
section(
|
||||
section({ id: "export" },
|
||||
div({ class: "tags-header" },
|
||||
h2(i18n.exportDataTitle),
|
||||
p(i18n.exportDataDescription),
|
||||
|
|
@ -378,7 +450,7 @@ const settingsView = ({ version, aiPrompt, fediverseAccount, fediverseError }) =
|
|||
)
|
||||
)
|
||||
),
|
||||
section(
|
||||
section({ id: "panic" },
|
||||
div({ class: "tags-header" },
|
||||
h2(i18n.panicMode),
|
||||
p(i18n.removeDataDescription),
|
||||
|
|
@ -388,6 +460,136 @@ const settingsView = ({ version, aiPrompt, fediverseAccount, fediverseError }) =
|
|||
)
|
||||
)
|
||||
)
|
||||
];
|
||||
const multiverseParts = modOn('fediverse') ? [
|
||||
section({ id: "mastodon" },
|
||||
div({ class: "tags-header" },
|
||||
h2("Mastodon"),
|
||||
fediverseAccount
|
||||
? (() => {
|
||||
const host = String(fediverseAccount.instance || "").replace(/^https?:\/\//, "");
|
||||
const profileUrl = `${fediverseAccount.instance}/@${fediverseAccount.acct}`;
|
||||
const link = (txt) => a({ href: profileUrl, target: "_blank", rel: "noopener noreferrer" }, txt);
|
||||
return form(
|
||||
{ action: "/settings/fediverse/disconnect", method: "POST" },
|
||||
p(
|
||||
`${i18n.fediverseConnectedAs}: `,
|
||||
link(`${fediverseAccount.acct}@${host}`)
|
||||
),
|
||||
button({ type: "submit" }, i18n.fediverseDisconnect)
|
||||
);
|
||||
})()
|
||||
: form(
|
||||
{ action: "/settings/fediverse", method: "POST" },
|
||||
label({ for: "fediverse_instance" }, i18n.fediverseInstanceLabel), br(),
|
||||
input({ type: "text", id: "fediverse_instance", name: "instance", placeholder: "mastodon.social", required: true }), br(),
|
||||
label({ for: "fediverse_token" }, i18n.fediverseTokenLabel), br(),
|
||||
input({ type: "password", id: "fediverse_token", name: "token", autocomplete: "off", required: true }), br(),
|
||||
button({ type: "submit" }, i18n.fediverseConnect)
|
||||
)
|
||||
)
|
||||
),
|
||||
section({ id: "telegram" },
|
||||
div({ class: "tags-header" },
|
||||
h2("Telegram"),
|
||||
telegramAccount
|
||||
? form(
|
||||
{ action: "/settings/telegram/disconnect", method: "POST" },
|
||||
p(`${i18n.fediverseConnectedAs}: `, strong(telegramAccount.displayName || ""), telegramAccount.username ? span(` (@${telegramAccount.username})`) : ""),
|
||||
br(),
|
||||
button({ type: "submit" }, i18n.fediverseDisconnect)
|
||||
)
|
||||
: telegramLogin && telegramLogin.step === "code"
|
||||
? form(
|
||||
{ action: "/settings/telegram/code", method: "POST" },
|
||||
br(),
|
||||
p(i18n.telegramCodeHelp),
|
||||
input({ type: "text", id: "telegram_code", name: "code", autocomplete: "off", inputmode: "numeric", placeholder: "12345", required: true }), br(), br(),
|
||||
button({ type: "submit" }, i18n.telegramVerify),
|
||||
" ",
|
||||
button({ type: "submit", formaction: "/settings/telegram/cancel", class: "delete-btn" }, i18n.telegramCancel)
|
||||
)
|
||||
: telegramLogin && telegramLogin.step === "password"
|
||||
? form(
|
||||
{ action: "/settings/telegram/password", method: "POST" },
|
||||
br(),
|
||||
p(i18n.telegramPasswordHelp),
|
||||
input({ type: "password", id: "telegram_password", name: "password", autocomplete: "off", required: true }), br(), br(),
|
||||
button({ type: "submit" }, i18n.telegramVerify),
|
||||
" ",
|
||||
button({ type: "submit", formaction: "/settings/telegram/cancel", class: "delete-btn" }, i18n.telegramCancel)
|
||||
)
|
||||
: form(
|
||||
{ action: "/settings/telegram/start", method: "POST" },
|
||||
label({ for: "telegram_api_id" }, i18n.telegramApiIdLabel), br(),
|
||||
input({ type: "text", id: "telegram_api_id", name: "apiId", inputmode: "numeric", placeholder: "12345678", required: true }), br(),
|
||||
label({ for: "telegram_api_hash" }, i18n.fediverseTokenLabel), br(),
|
||||
input({ type: "password", id: "telegram_api_hash", name: "apiHash", autocomplete: "off", placeholder: "0123456789abcdef0123456789abcdef", required: true }), br(),
|
||||
label({ for: "telegram_phone" }, i18n.telegramPhoneLabel), br(),
|
||||
input({ type: "tel", id: "telegram_phone", name: "phone", placeholder: "+34 60000000", required: true }), br(), br(),
|
||||
button({ type: "submit" }, i18n.fediverseConnect)
|
||||
)
|
||||
)
|
||||
),
|
||||
section({ id: "peertube" },
|
||||
div({ class: "tags-header" },
|
||||
h2("PeerTube"),
|
||||
peertubeAccount
|
||||
? form(
|
||||
{ action: "/settings/peertube/disconnect", method: "POST" },
|
||||
p(`${i18n.fediverseConnectedAs}: `, a({ href: peertubeAccount.channelUrl || peertubeAccount.profileUrl, target: "_blank", rel: "noopener noreferrer" }, peertubeAccount.handle)),
|
||||
button({ type: "submit" }, i18n.fediverseDisconnect)
|
||||
)
|
||||
: form(
|
||||
{ action: "/settings/peertube", method: "POST" },
|
||||
label({ for: "peertube_instance" }, i18n.fediverseInstanceLabel), br(),
|
||||
input({ type: "text", id: "peertube_instance", name: "instance", placeholder: "peertube.example.org", required: true }), br(),
|
||||
label({ for: "peertube_username" }, i18n.peertubeUsernameLabel), br(),
|
||||
input({ type: "text", id: "peertube_username", name: "username", autocomplete: "off", required: true }), br(),
|
||||
label({ for: "peertube_password" }, i18n.peertubePasswordLabel), br(),
|
||||
input({ type: "password", id: "peertube_password", name: "password", autocomplete: "off", required: true }), br(),
|
||||
button({ type: "submit" }, i18n.fediverseConnect)
|
||||
)
|
||||
)
|
||||
)
|
||||
,
|
||||
section({ id: "nextcloud" },
|
||||
div({ class: "tags-header" },
|
||||
h2("Nextcloud"),
|
||||
nextcloudAccount
|
||||
? form(
|
||||
{ action: "/settings/nextcloud/disconnect", method: "POST" },
|
||||
p(`${i18n.fediverseConnectedAs}: `, a({ href: nextcloudAccount.server, target: "_blank", rel: "noopener noreferrer" }, `${nextcloudAccount.user}@${String(nextcloudAccount.server).replace(/^https?:\/\//, "")}`), ` (${nextcloudAccount.folder})`),
|
||||
button({ type: "submit" }, i18n.fediverseDisconnect)
|
||||
)
|
||||
: form(
|
||||
{ action: "/settings/nextcloud", method: "POST" },
|
||||
label({ for: "nextcloud_server" }, i18n.nextcloudServerLabel), br(),
|
||||
input({ type: "text", id: "nextcloud_server", name: "server", placeholder: "cloud.example.org", required: true }), br(),
|
||||
label({ for: "nextcloud_user" }, i18n.nextcloudUserLabel), br(),
|
||||
input({ type: "text", id: "nextcloud_user", name: "user", autocomplete: "off", required: true }), br(),
|
||||
label({ for: "nextcloud_password" }, i18n.peertubePasswordLabel), br(),
|
||||
input({ type: "password", id: "nextcloud_password", name: "password", autocomplete: "off", required: true }), br(),
|
||||
label({ for: "nextcloud_folder" }, i18n.nextcloudFolderLabel), br(),
|
||||
input({ type: "text", id: "nextcloud_folder", name: "folder", placeholder: "Oasis" }), br(),
|
||||
button({ type: "submit" }, i18n.fediverseConnect)
|
||||
)
|
||||
)
|
||||
)
|
||||
] : [];
|
||||
return template(
|
||||
i18n.settings,
|
||||
section(
|
||||
div({ class: "tags-header module-header-line" },
|
||||
h2(i18n.settings),
|
||||
p(i18n.settingsDescription)
|
||||
),
|
||||
div({ class: "mode-buttons-row" },
|
||||
a({ class: filter === 'oasis' ? 'filter-btn active' : 'filter-btn', href: '/settings?filter=oasis' }, String(i18n.linkBoxOasis).toUpperCase()),
|
||||
modOn('fediverse') ? a({ class: filter === 'multiverse' ? 'filter-btn active' : 'filter-btn', href: '/settings?filter=multiverse' }, String(i18n.multiverse).toUpperCase()) : null
|
||||
)
|
||||
),
|
||||
...(filter === 'multiverse' ? multiverseParts : oasisParts)
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue