mirror of
https://github.com/screentinker/screentinker.git
synced 2026-06-15 10:43:36 -06:00
MSP-style deployments want self-service signups created WITHOUT a personal
org, so an admin/operator can assign them into an existing customer org
afterward.
- config.autoCreateOrgOnSignup (AUTO_CREATE_ORG_ON_SIGNUP env), default
true - single-tenant and the hosted self-service flow are unchanged.
- ensureDefaultOrgForUser gains { allowCreate }: an existing membership is
always returned (idempotent); the MINT path is gated. allowCreate=false +
no membership -> returns null (user created org-less).
- register accepts a per-request createOrg flag overriding the deployment
default; the first-ever user is always given an org (never headless).
login / Google / Microsoft pass allowCreate from the global config, so an
org-less user is not silently given an org on next sign-in.
Edge case: a non-platform user with zero workspaces now lands on a "no
workspaces yet" empty state (new no-workspace view) instead of being bounced
into onboarding (whose pairing step needs a workspace). route() redirects
them there, and refreshCurrentUser() redirects once /me reveals zero
accessible_workspaces (covers the first-load race). The workspace switcher
already rendered an empty placeholder and resource routes already return []
for a null workspace, so nothing crashes in between.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
32 lines
1.5 KiB
JavaScript
32 lines
1.5 KiB
JavaScript
// #12: empty state for a signed-in user who belongs to zero workspaces. Happens
|
|
// on deployments with AUTO_CREATE_ORG_ON_SIGNUP=false, where a self-service
|
|
// signup is created org-less and an admin/operator assigns them to a workspace
|
|
// afterward. Without this, such a user would be bounced into onboarding (whose
|
|
// device-pairing step needs a workspace) - a broken flow. Here they get a clear
|
|
// "ask your admin" message instead.
|
|
import { t } from '../i18n.js';
|
|
|
|
export function render(container) {
|
|
container.innerHTML = `
|
|
<div style="display:flex;align-items:center;justify-content:center;min-height:100vh;padding:16px">
|
|
<div style="width:440px;max-width:100%;text-align:center">
|
|
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="var(--text-muted)" stroke-width="1.6" style="margin:0 auto 16px">
|
|
<rect x="3" y="4" width="18" height="14" rx="2"/>
|
|
<path d="M3 9h18"/>
|
|
</svg>
|
|
<h1 style="font-size:20px;font-weight:700;margin-bottom:8px">${t('noworkspace.title')}</h1>
|
|
<p style="color:var(--text-secondary);font-size:14px;line-height:1.6;margin-bottom:24px">${t('noworkspace.body')}</p>
|
|
<button class="btn btn-secondary" id="noWsSignOut" style="padding:8px 16px">${t('noworkspace.sign_out')}</button>
|
|
</div>
|
|
</div>
|
|
`;
|
|
container.querySelector('#noWsSignOut').addEventListener('click', () => {
|
|
localStorage.removeItem('token');
|
|
localStorage.removeItem('user');
|
|
window.location.hash = '#/login';
|
|
window.location.reload();
|
|
});
|
|
}
|
|
|
|
export function cleanup() {}
|