diff --git a/modules/rinbox/mod.ts b/modules/rinbox/mod.ts index 5579c78..60938ba 100644 --- a/modules/rinbox/mod.ts +++ b/modules/rinbox/mod.ts @@ -458,6 +458,8 @@ async function executeApproval(docId: string, approvalId: string) { replyTo: agentReplyTo, subject: approval.subject, text: approval.bodyText, + // Envelope override: authenticate as SMTP_USER but show mailboxEmail in From header + envelope: { from: SMTP_USER || 'noreply@rmail.online', to: approval.toAddresses }, }; if (approval.ccAddresses.length > 0) { diff --git a/server/shell.ts b/server/shell.ts index 3e12776..edc043a 100644 --- a/server/shell.ts +++ b/server/shell.ts @@ -607,10 +607,19 @@ export function renderShell(opts: ShellOptions): string { var enabledModules = detail.enabledModules; window.__rspaceEnabledModules = enabledModules; - // Update tab bar's module list + // Recompute visible + allModules with updated enabled flags var allMods = window.__rspaceAllModules || []; var enabledSet = new Set(enabledModules); var visible = allMods.filter(function(m) { return m.id === 'rspace' || enabledSet.has(m.id); }); + var updatedAll = allMods.map(function(m) { return Object.assign({}, m, { enabled: m.id === 'rspace' || enabledSet.has(m.id) }); }); + window.__rspaceModuleList = visible; + window.__rspaceAllModules = updatedAll; + + // Update app switcher's main navigation + catalog + var switcher = document.querySelector('rstack-app-switcher'); + if (switcher) { switcher.setModules(visible); switcher.setAllModules(updatedAll); } + + // Update tab bar's module list var tb = document.querySelector('rstack-tab-bar'); if (tb) tb.setModules(visible); diff --git a/server/spaces.ts b/server/spaces.ts index 8549923..1970a9e 100644 --- a/server/spaces.ts +++ b/server/spaces.ts @@ -2199,11 +2199,14 @@ spaces.post("/:slug/invite", async (c) => { metadata: { inviteToken: invite.token, role }, }).catch(() => {}); - // Send invite email + // Send invite email from {slug}-agent@rspace.online if (inviteTransport) { try { + const agentAddr = `${slug}-agent@rspace.online`; await inviteTransport.sendMail({ - from: process.env.SMTP_FROM || "rSpace ", + from: `${slug} <${agentAddr}>`, + replyTo: agentAddr, + envelope: { from: process.env.SMTP_USER || "noreply@rmail.online", to: body.email }, to: body.email, subject: `${inviterName} invited you to "${slug}" on rSpace`, html: ` @@ -2326,11 +2329,14 @@ spaces.post("/:slug/members/add", async (c) => { metadata: { inviteToken: invite.token, role }, }).catch(() => {}); - // Send invite email (non-fatal) + // Send invite email from {slug}-agent@rspace.online (non-fatal) if (inviteTransport && targetEmail) { try { + const agentAddr = `${slug}-agent@rspace.online`; await inviteTransport.sendMail({ - from: process.env.SMTP_FROM || "rSpace ", + from: `${slug} <${agentAddr}>`, + replyTo: agentAddr, + envelope: { from: process.env.SMTP_USER || "noreply@rmail.online", to: targetEmail }, to: targetEmail, subject: `${inviterName} invited you to "${slug}" on rSpace`, html: ` diff --git a/shared/components/rstack-app-switcher.ts b/shared/components/rstack-app-switcher.ts index 3da8a95..7a2bfe8 100644 --- a/shared/components/rstack-app-switcher.ts +++ b/shared/components/rstack-app-switcher.ts @@ -243,34 +243,37 @@ export class RStackAppSwitcher extends HTMLElement { const disabledModules = this.#allModules.filter( m => m.enabled === false && m.id !== 'rspace' ); - if (disabledModules.length > 0 || this.#allModules.length > 0) { + // Only show the Manage section when there are disabled modules to add, + // or when enabledModules is actively configured (not null/all-enabled) + const hasRestrictions = disabledModules.length > 0; + if (hasRestrictions || this.#allModules.length > this.#modules.length) { html += `
`; if (this.#catalogOpen) { html += `
`; - // Show enabled modules with toggle-off option - const enabledNonCore = this.#allModules.filter( - m => m.enabled !== false && m.id !== 'rspace' - ); - if (enabledNonCore.length > 0) { - html += ``; - for (const m of enabledNonCore) { - html += this.#renderCatalogItem(m, true); - } - } - // Show disabled modules with toggle-on option + // Show disabled modules with add option if (disabledModules.length > 0) { html += ``; for (const m of disabledModules) { html += this.#renderCatalogItem(m, false); } } + // Show enabled modules with remove option (compact section below) + const enabledNonCore = this.#allModules.filter( + m => m.enabled !== false && m.id !== 'rspace' + ); + if (enabledNonCore.length > 0) { + html += ``; + for (const m of enabledNonCore) { + html += this.#renderCatalogItem(m, true); + } + } html += `
`; } } diff --git a/src/encryptid/server.ts b/src/encryptid/server.ts index 48c8465..f255407 100644 --- a/src/encryptid/server.ts +++ b/src/encryptid/server.ts @@ -5462,8 +5462,11 @@ app.post('/api/invites/identity', async (c) => { const subjectLine = spaceSlug ? `${payload.username} invited you to join "${spaceSlug}" on rSpace` : `${payload.username} invited you to join rSpace`; + const agentAddr = spaceSlug ? `${spaceSlug}-agent@rspace.online` : null; await smtpTransport.sendMail({ - from: CONFIG.smtp.from, + from: agentAddr ? `${spaceSlug} <${agentAddr}>` : CONFIG.smtp.from, + ...(agentAddr ? { replyTo: agentAddr } : {}), + ...(agentAddr ? { envelope: { from: CONFIG.smtp.user, to: email } } : {}), to: email, subject: subjectLine, html: ` diff --git a/website/public/shell.css b/website/public/shell.css index 7676814..6c0b02f 100644 --- a/website/public/shell.css +++ b/website/public/shell.css @@ -15,7 +15,7 @@ body { .rspace-banner { position: fixed; top: 0; left: 0; right: 0; - z-index: 10002; + z-index: 10000; /* above header (9999) */ display: flex; align-items: center; justify-content: center; @@ -68,7 +68,7 @@ body { .rspace-banner__close:hover { color: #fff; } -/* Push header down when a banner is visible */ +/* Push header + content down when a banner is visible */ body.rspace-banner-visible .rstack-header { top: 36px; } @@ -628,13 +628,13 @@ body.rspace-headers-minimized .rapp-subnav { /* Smooth transitions for header minimize/restore */ .rstack-header { - transition: transform 0.25s ease; + transition: transform 0.25s ease, top 0.3s ease-out; } .rstack-tab-row { - transition: margin-left 0.25s ease, left 0.25s ease, transform 0.25s ease; + transition: margin-left 0.25s ease, left 0.25s ease, transform 0.25s ease, top 0.3s ease-out; } #app { - transition: margin-left 0.25s ease, left 0.25s ease, padding-top 0.25s ease; + transition: margin-left 0.25s ease, left 0.25s ease, padding-top 0.3s ease-out; } /* Mobile: minimized state adjustments (sticky, not fixed) */