feat: bootstrap 2 users, tenant, org-scoped tokens, platform admin UI
Bootstrap script now creates: - SaaS Owner (admin/admin) with platform-admin role - Tenant Admin (camel/camel) in Example Tenant org - Traditional Web App for cameleer3-server OIDC - DB records: tenant, default environment, license - Configures cameleer3-server OIDC via its admin API All credentials configurable via env vars. Backend: - Fix LogtoManagementClient resource URL (https://default.logto.app/api) - Add getUserRoles/getUserOrganizations to LogtoManagementClient - Add GET /api/me endpoint (user info, platform admin status, tenants) - Add GET /api/tenants list-all for platform admins - Remove insecure X-header forwarding from Traefik Frontend: - Org-scoped tokens: getAccessToken(resource, orgId) for tenant context - OrgResolver component populates org store from /api/me - useOrganization Zustand store (currentOrgId + currentTenantId) - Platform admin sidebar section + AdminTenantsPage - View Dashboard link points to cameleer3-server on port 8081 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -89,9 +89,18 @@ function UserIcon() {
|
||||
);
|
||||
}
|
||||
|
||||
function PlatformIcon() {
|
||||
return (
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true">
|
||||
<path d="M8 1l6 3.5v7L8 15l-6-3.5v-7L8 1z" stroke="currentColor" strokeWidth="1.5" />
|
||||
<path d="M8 1v14M2 4.5L14 4.5M2 11.5L14 11.5" stroke="currentColor" strokeWidth="1" opacity="0.4" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export function Layout() {
|
||||
const navigate = useNavigate();
|
||||
const { username, logout } = useAuth();
|
||||
const { username, logout, isPlatformAdmin } = useAuth();
|
||||
|
||||
const [envSectionOpen, setEnvSectionOpen] = useState(true);
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
@@ -134,12 +143,24 @@ export function Layout() {
|
||||
{null}
|
||||
</Sidebar.Section>
|
||||
|
||||
{/* Platform Admin section */}
|
||||
{isPlatformAdmin && (
|
||||
<Sidebar.Section
|
||||
icon={<PlatformIcon />}
|
||||
label="Platform"
|
||||
open={false}
|
||||
onToggle={() => navigate('/admin/tenants')}
|
||||
>
|
||||
{null}
|
||||
</Sidebar.Section>
|
||||
)}
|
||||
|
||||
<Sidebar.Footer>
|
||||
{/* Link to the observability SPA (external) */}
|
||||
{/* Link to the observability SPA (direct port, not via Traefik prefix) */}
|
||||
<Sidebar.FooterLink
|
||||
icon={<ObsIcon />}
|
||||
label="View Dashboard"
|
||||
onClick={() => window.open('/dashboard', '_blank', 'noopener')}
|
||||
onClick={() => window.open('http://localhost:8081', '_blank', 'noopener')}
|
||||
/>
|
||||
|
||||
{/* User info + logout */}
|
||||
|
||||
Reference in New Issue
Block a user