575 lines
32 KiB
HTML
575 lines
32 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<base href="../">
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Crank — Settings</title>
|
||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
||
<link rel="stylesheet" href="css/variables.css">
|
||
<link rel="stylesheet" href="css/layout.css">
|
||
<link rel="stylesheet" href="css/pages.css">
|
||
<link rel="stylesheet" href="css/settings.css">
|
||
<script src="js/config.js"></script>
|
||
<script src="js/i18n.js"></script>
|
||
<script src="js/api.js"></script>
|
||
<script src="js/workspace.js"></script>
|
||
<script src="js/auth.js"></script>
|
||
<script>window.CrankAuth.guardProtectedPage();</script>
|
||
</head>
|
||
<body>
|
||
|
||
<nav class="navbar">
|
||
<a href="index.html" class="nav-logo">
|
||
<div class="nav-logo-mark"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 28 28" fill="white"><path fill-rule="evenodd" d="M 10.000,1.800 L 12.287,3.962 L 15.408,3.557 L 15.987,6.650 L 18.750,8.157 L 17.400,11.000 L 18.750,13.843 L 15.987,15.350 L 15.408,18.443 L 12.287,18.038 L 10.000,20.200 L 7.713,18.038 L 4.592,18.443 L 4.013,15.350 L 1.250,13.843 L 2.600,11.000 L 1.250,8.157 L 4.013,6.650 L 4.592,3.557 L 7.713,3.962 Z M 12.800,11.000 A 2.8 2.8 0 1 0 7.200,11.000 A 2.8 2.8 0 1 0 12.800,11.000 Z"/><path fill-rule="evenodd" d="M 11.791,15.604 Q 16.083,17.179 21.375,21.154 A 2.00 2.00 0 1 1 23.625,17.846 Q 19.782,15.610 14.940,10.973 Z M 24.300,19.500 A 1.8 1.8 0 1 0 20.700,19.500 A 1.8 1.8 0 1 0 24.300,19.500 Z"/><path d="M 10.0,9.7 L 11.3,11.0 L 10.0,12.3 L 8.7,11.0 Z" fill="rgba(0,0,0,0.3)"/></svg></div>
|
||
<span class="nav-logo-text">Crank</span>
|
||
</a>
|
||
|
||
<!-- Workspace switcher -->
|
||
<div class="ws-switcher" id="ws-switcher">
|
||
<button class="ws-switcher-trigger" onclick="toggleWsSwitcher(event)">
|
||
<div class="ws-dot" id="ws-dot">A</div>
|
||
<span class="ws-current-name" id="ws-current-name">acme-workspace</span>
|
||
<svg width="11" height="11" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 6l4 4 4-4"/></svg>
|
||
</button>
|
||
<div class="ws-dropdown" id="ws-dropdown" style="display:none">
|
||
<div class="ws-dropdown-label">Your workspaces</div>
|
||
<div id="ws-dropdown-list"></div>
|
||
<div class="ws-dropdown-footer">
|
||
<button class="ws-dropdown-create" onclick="window.location.href='workspace-setup.html?mode=create'">
|
||
<svg width="12" height="12" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><path d="M8 3v10M3 8h10"/></svg>
|
||
Create workspace
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="nav-links">
|
||
<a href="index.html" class="nav-link" data-i18n="nav.operations">Operations</a>
|
||
<a href="html/agents.html" class="nav-link" data-i18n="nav.agents">Agents</a>
|
||
<a href="html/api-keys.html" class="nav-link" data-i18n="nav.apikeys">API Keys</a>
|
||
<a href="html/logs.html" class="nav-link" data-i18n="nav.logs">Logs</a>
|
||
<a href="html/usage.html" class="nav-link" data-i18n="nav.usage">Usage</a>
|
||
</div>
|
||
<div class="nav-right">
|
||
<button class="nav-hamburger" aria-label="Menu"><span></span><span></span><span></span></button>
|
||
<div class="nav-kbd">
|
||
<svg width="12" height="12"><use href="icons/general/grid.svg#icon"/></svg>
|
||
<span>⌘K</span>
|
||
</div>
|
||
<button class="nav-icon-btn" title="Notifications">
|
||
<svg width="15" height="15"><use href="icons/general/bell.svg#icon"/></svg>
|
||
</button>
|
||
<div class="nav-divider"></div>
|
||
<div class="user-menu">
|
||
<div class="nav-avatar" title="Account">AT</div>
|
||
<div class="user-dropdown">
|
||
<div class="user-dropdown-header">
|
||
<div class="user-dropdown-name">Operator</div>
|
||
<div class="user-dropdown-role">Admin · acme-workspace</div>
|
||
</div>
|
||
<button class="user-dropdown-item" data-action="settings-link">
|
||
<svg width="13" height="13"><use href="icons/general/settings.svg#icon"/></svg>
|
||
<span data-i18n="nav.settings">Settings</span>
|
||
</button>
|
||
<div class="dropdown-divider"></div>
|
||
<button class="user-dropdown-item danger" data-action="logout">
|
||
<svg width="13" height="13"><use href="icons/general/logout.svg#icon"/></svg>
|
||
<span data-i18n="nav.logout">Log out</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</nav>
|
||
|
||
<div class="mobile-nav">
|
||
<a href="index.html" class="mobile-nav-link" data-i18n="nav.operations">Operations</a>
|
||
<a href="html/agents.html" class="mobile-nav-link" data-i18n="nav.agents">Agents</a>
|
||
<a href="html/api-keys.html" class="mobile-nav-link" data-i18n="nav.apikeys">API Keys</a>
|
||
<a href="html/logs.html" class="mobile-nav-link" data-i18n="nav.logs">Logs</a>
|
||
<a href="html/usage.html" class="mobile-nav-link" data-i18n="nav.usage">Usage</a>
|
||
</div>
|
||
|
||
<div class="page">
|
||
|
||
<div class="page-header" style="margin-bottom: 24px;">
|
||
<div class="page-header-text">
|
||
<h1 class="page-title">Account settings</h1>
|
||
<p class="page-subtitle">Manage your personal profile, security, and notification preferences.</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="settings-layout">
|
||
|
||
<!-- ── Sidebar nav ── -->
|
||
<nav class="settings-nav" id="settings-nav">
|
||
<button class="settings-nav-item" data-section="workspace">
|
||
<svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M2 5.5h12M4 2.5h8a1.5 1.5 0 011.5 1.5v8A1.5 1.5 0 0112 13.5H4A1.5 1.5 0 012.5 12V4A1.5 1.5 0 014 2.5z"/>
|
||
</svg>
|
||
<span>Workspace</span>
|
||
</button>
|
||
<button class="settings-nav-item active" data-section="profile">
|
||
<svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round">
|
||
<circle cx="8" cy="5" r="3"/>
|
||
<path d="M1.5 14.5c0-3.314 2.91-6 6.5-6s6.5 2.686 6.5 6"/>
|
||
</svg>
|
||
<span data-i18n="settings.nav.profile">Profile</span>
|
||
</button>
|
||
<button class="settings-nav-item" data-section="security">
|
||
<svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M8 1L2 3.5v4.5C2 11.3 4.7 14.4 8 15c3.3-.6 6-3.7 6-7V3.5L8 1z"/>
|
||
</svg>
|
||
<span data-i18n="settings.nav.security">Security</span>
|
||
</button>
|
||
<button class="settings-nav-item" data-section="notifications">
|
||
<svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M8 1.5a5 5 0 015 5v2.5l1 2H2l1-2V6.5a5 5 0 015-5z"/>
|
||
<path d="M6.5 13a1.5 1.5 0 003 0"/>
|
||
</svg>
|
||
<span data-i18n="settings.nav.notif">Notifications</span>
|
||
</button>
|
||
</nav>
|
||
|
||
<!-- ── Content ── -->
|
||
<div id="settings-content">
|
||
|
||
<div id="section-workspace" class="section-anchor">
|
||
<div class="section-card" style="margin-bottom: 20px;">
|
||
<div class="section-card-header">
|
||
<div>
|
||
<div class="section-card-title" data-i18n="settings.ws.title">Workspace settings</div>
|
||
<div class="section-card-subtitle" data-i18n="settings.ws.subtitle">General information about your workspace</div>
|
||
</div>
|
||
</div>
|
||
<div class="section-card-body" style="padding-bottom:8px;">
|
||
<div class="field-group">
|
||
<label class="field-label" data-i18n="settings.ws.name">Workspace name</label>
|
||
<input class="field-input" id="settings-ws-slug" type="text" value="acme-workspace" autocomplete="off">
|
||
<div class="field-hint">Used in API endpoints and across the console. Only lowercase letters, numbers and hyphens.</div>
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label" data-i18n="settings.ws.display">Display name</label>
|
||
<input class="field-input" id="settings-ws-display-name" type="text" value="Acme Corp" autocomplete="off">
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label">Description <span style="font-size:11px;color:var(--text-muted);">(optional)</span></label>
|
||
<textarea class="field-textarea" id="settings-ws-description" rows="2" placeholder="What does this workspace do?">Primary production workspace for CRM and e-commerce API operations.</textarea>
|
||
</div>
|
||
<div class="field-row">
|
||
<div class="field-group">
|
||
<label class="field-label" data-i18n="settings.ws.tz">Timezone</label>
|
||
<select class="field-select" id="settings-ws-timezone">
|
||
<option selected>UTC</option>
|
||
<option>America/New_York</option>
|
||
<option>America/Los_Angeles</option>
|
||
<option>Europe/London</option>
|
||
<option>Europe/Paris</option>
|
||
<option>Asia/Tokyo</option>
|
||
</select>
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label" data-i18n="settings.ws.protocol">Default protocol</label>
|
||
<select class="field-select" id="settings-ws-protocol">
|
||
<option value="rest" selected>REST / HTTP</option>
|
||
<option value="graphql">GraphQL</option>
|
||
<option value="grpc">gRPC</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<!-- Language -->
|
||
<div class="field-group" style="margin-top:4px;">
|
||
<label class="field-label">
|
||
<span data-i18n="settings.lang.title">Language</span>
|
||
</label>
|
||
<div class="lang-switcher">
|
||
<button class="lang-btn active" data-lang="en" onclick="setLang('en')">
|
||
<span class="lang-flag">🇬🇧</span>
|
||
<span data-i18n="settings.lang.en">English</span>
|
||
</button>
|
||
<button class="lang-btn" data-lang="ru" onclick="setLang('ru')">
|
||
<span class="lang-flag">🇷🇺</span>
|
||
<span data-i18n="settings.lang.ru">Русский</span>
|
||
</button>
|
||
</div>
|
||
<div class="field-hint" data-i18n="settings.lang.subtitle">Interface display language</div>
|
||
</div>
|
||
|
||
<div style="display:flex;justify-content:flex-end;padding-top:4px;">
|
||
<button class="btn-primary" id="settings-ws-save-btn" type="button"><span data-i18n="btn.save">Save changes</span></button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ■ PROFILE ■ -->
|
||
<div id="section-profile" class="section-anchor">
|
||
<div class="section-card" style="margin-bottom: 20px;">
|
||
<div class="section-card-header">
|
||
<div class="section-card-title" data-i18n="settings.profile.title">Profile</div>
|
||
</div>
|
||
<div class="section-card-body">
|
||
<div class="avatar-upload">
|
||
<div class="avatar-large" id="profile-avatar">AT</div>
|
||
<div class="avatar-upload-actions">
|
||
<div class="avatar-name" id="profile-display-name">Operator</div>
|
||
<div class="avatar-sub" id="profile-email">operator@acme-workspace</div>
|
||
<div class="field-hint">Profile photo upload is not available yet.</div>
|
||
</div>
|
||
</div>
|
||
<div class="field-hint" style="margin-bottom:16px;">Your name and email are stored on the backend and used across the console.</div>
|
||
|
||
<div class="field-row">
|
||
<div class="field-group">
|
||
<label class="field-label">First name</label>
|
||
<input class="field-input" id="field-firstname" type="text" value="Operator" autocomplete="given-name">
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label">Last name</label>
|
||
<input class="field-input" id="field-lastname" type="text" value="" autocomplete="family-name" placeholder="Optional">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="field-group">
|
||
<label class="field-label">Email address</label>
|
||
<input class="field-input" id="field-email" type="email" value="operator@acme.com" autocomplete="email">
|
||
<div class="field-hint">Changing email updates the login identity for the current account.</div>
|
||
</div>
|
||
|
||
<div class="field-hint" id="settings-profile-status" style="margin-bottom:12px;"></div>
|
||
<div style="display:flex;justify-content:flex-end;">
|
||
<button class="btn-primary" id="settings-profile-save-btn" type="button">Save profile</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ■ MEMBERS — moved to workspace-setup.html ■ -->
|
||
<div id="section-members" style="display:none;">
|
||
|
||
<!-- Members card -->
|
||
<div class="section-card" style="margin-bottom: 16px;">
|
||
<div class="section-card-header">
|
||
<div>
|
||
<div class="section-card-title">Team members</div>
|
||
<div class="section-card-subtitle" id="members-count-label">4 members</div>
|
||
</div>
|
||
<button class="btn-primary" type="button" style="padding:7px 14px;font-size:13px;" onclick="toggleInviteForm()">
|
||
<svg width="12" height="12" viewBox="0 0 16 16" fill="currentColor" style="margin-right:4px;"><path d="M7.75 2a.75.75 0 01.75.75V7h4.25a.75.75 0 010 1.5H8.5v4.25a.75.75 0 01-1.5 0V8.5H2.75a.75.75 0 010-1.5H7V2.75A.75.75 0 017.75 2z"/></svg>
|
||
Invite member
|
||
</button>
|
||
</div>
|
||
|
||
<!-- Invite form -->
|
||
<div id="invite-form" style="display:none; padding: 0 20px 16px; border-bottom: 1px solid var(--border-subtle);">
|
||
<div style="display:flex; gap:10px; align-items:flex-end; flex-wrap:wrap;">
|
||
<div class="field-group" style="flex:1; min-width:200px; margin-bottom:0;">
|
||
<label class="field-label">Email address</label>
|
||
<input class="field-input" id="invite-email" type="email" placeholder="colleague@company.com" autocomplete="off">
|
||
</div>
|
||
<div class="field-group" style="width:150px; margin-bottom:0;">
|
||
<label class="field-label">Role</label>
|
||
<select class="field-input" id="invite-role">
|
||
<option value="admin">Admin</option>
|
||
<option value="developer" selected>Developer</option>
|
||
<option value="viewer">Viewer</option>
|
||
</select>
|
||
</div>
|
||
<button class="btn-primary" type="button" style="padding:7px 14px;font-size:13px;white-space:nowrap;" onclick="sendInvite()">Send invite</button>
|
||
<button class="btn-secondary" type="button" style="padding:7px 12px;font-size:13px;" onclick="toggleInviteForm()">Cancel</button>
|
||
</div>
|
||
<div id="invite-success" style="display:none; margin-top:10px; font-size:13px; color: #3fb950;">
|
||
✓ Invite sent successfully.
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Members list -->
|
||
<div class="section-card-body" style="padding: 4px 20px 8px;" id="members-list">
|
||
<!-- Owner row (you) -->
|
||
<div class="member-row">
|
||
<div class="member-avatar" style="background:linear-gradient(135deg,#0d9488,#6366f1);">AT</div>
|
||
<div class="member-info">
|
||
<div class="member-name">Operator <span style="font-size:11px;font-weight:400;color:var(--text-muted);">(you)</span></div>
|
||
<div class="member-email">operator@acme.com</div>
|
||
</div>
|
||
<div class="member-last-active">Today</div>
|
||
<span class="member-role-badge role-owner">Owner</span>
|
||
</div>
|
||
<!-- Admin -->
|
||
<div class="member-row">
|
||
<div class="member-avatar" style="background:linear-gradient(135deg,#7c3aed,#4f46e5);">BS</div>
|
||
<div class="member-info">
|
||
<div class="member-name">Blake Smith</div>
|
||
<div class="member-email">blake@acme.com</div>
|
||
</div>
|
||
<div class="member-last-active">2 days ago</div>
|
||
<select class="member-role-select" onchange="updateRole(this, 'blake@acme.com')">
|
||
<option value="admin" selected>Admin</option>
|
||
<option value="developer">Developer</option>
|
||
<option value="viewer">Viewer</option>
|
||
</select>
|
||
<button class="member-remove-btn" onclick="removeMember(this, 'Blake Smith')" title="Remove member">
|
||
<svg width="12" height="12" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M2 4h12M5 4V3a1 1 0 011-1h4a1 1 0 011 1v1M10 8v4M6 8v4"/><path d="M3 4l1 9a1 1 0 001 1h6a1 1 0 001-1l1-9"/></svg>
|
||
</button>
|
||
</div>
|
||
<!-- Developer -->
|
||
<div class="member-row">
|
||
<div class="member-avatar" style="background:linear-gradient(135deg,#d29922,#f59e0b);">CL</div>
|
||
<div class="member-info">
|
||
<div class="member-name">Carol Lane</div>
|
||
<div class="member-email">carol@acme.com</div>
|
||
</div>
|
||
<div class="member-last-active">1 week ago</div>
|
||
<select class="member-role-select" onchange="updateRole(this, 'carol@acme.com')">
|
||
<option value="admin">Admin</option>
|
||
<option value="developer" selected>Developer</option>
|
||
<option value="viewer">Viewer</option>
|
||
</select>
|
||
<button class="member-remove-btn" onclick="removeMember(this, 'Carol Lane')" title="Remove member">
|
||
<svg width="12" height="12" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M2 4h12M5 4V3a1 1 0 011-1h4a1 1 0 011 1v1M10 8v4M6 8v4"/><path d="M3 4l1 9a1 1 0 001 1h6a1 1 0 001-1l1-9"/></svg>
|
||
</button>
|
||
</div>
|
||
<!-- Viewer -->
|
||
<div class="member-row">
|
||
<div class="member-avatar" style="background:linear-gradient(135deg,#0891b2,#06b6d4);">DM</div>
|
||
<div class="member-info">
|
||
<div class="member-name">Dan Morgan</div>
|
||
<div class="member-email">dan@acme.com</div>
|
||
</div>
|
||
<div class="member-last-active">Never</div>
|
||
<select class="member-role-select" onchange="updateRole(this, 'dan@acme.com')">
|
||
<option value="admin">Admin</option>
|
||
<option value="developer">Developer</option>
|
||
<option value="viewer" selected>Viewer</option>
|
||
</select>
|
||
<button class="member-remove-btn" onclick="removeMember(this, 'Dan Morgan')" title="Remove member">
|
||
<svg width="12" height="12" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M2 4h12M5 4V3a1 1 0 011-1h4a1 1 0 011 1v1M10 8v4M6 8v4"/><path d="M3 4l1 9a1 1 0 001 1h6a1 1 0 001-1l1-9"/></svg>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Pending invites -->
|
||
<div id="pending-invites" style="border-top: 1px solid var(--border-subtle); padding: 12px 20px 16px;">
|
||
<div style="font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:0.06em;color:var(--text-muted);margin-bottom:10px;">Pending invites <span id="pending-count" style="background:rgba(139,148,158,0.15);border-radius:10px;padding:1px 7px;font-size:10px;">1</span></div>
|
||
<div class="member-row" id="invite-john">
|
||
<div class="member-avatar" style="background:var(--bg-canvas);border:1.5px dashed var(--border);color:var(--text-muted);font-size:16px;">?</div>
|
||
<div class="member-info">
|
||
<div class="member-name">john@startup.com</div>
|
||
<div class="member-email">Invited 3 days ago · not yet accepted</div>
|
||
</div>
|
||
<div class="member-last-active">—</div>
|
||
<span class="member-role-badge" style="background:rgba(139,148,158,0.12);color:var(--text-muted);border:1px solid var(--border);">Developer</span>
|
||
<button class="member-remove-btn" onclick="revokeInvite(this)" title="Revoke invite">
|
||
<svg width="12" height="12" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"><line x1="2" y1="2" x2="14" y2="14"/><line x1="14" y1="2" x2="2" y2="14"/></svg>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Roles & permissions reference -->
|
||
<div class="section-card" style="margin-bottom: 20px;">
|
||
<div class="section-card-header">
|
||
<div class="section-card-title">Roles & permissions</div>
|
||
</div>
|
||
<div class="section-card-body" style="padding: 4px 0 8px; gap: 0;">
|
||
<div class="role-def-row">
|
||
<span class="member-role-badge role-owner" style="min-width:80px;text-align:center;">Owner</span>
|
||
<div class="role-def-text">Full workspace control, billing access, can transfer or delete the workspace. Only one owner per workspace.</div>
|
||
</div>
|
||
<div class="role-def-row">
|
||
<span class="member-role-badge role-admin" style="min-width:80px;text-align:center;">Admin</span>
|
||
<div class="role-def-text">Manage members and roles, create and edit all operations and agents, manage API keys.</div>
|
||
</div>
|
||
<div class="role-def-row">
|
||
<span class="member-role-badge role-developer" style="min-width:80px;text-align:center;">Developer</span>
|
||
<div class="role-def-text">Create and edit operations and agents. Cannot manage members or workspace settings.</div>
|
||
</div>
|
||
<div class="role-def-row">
|
||
<span class="member-role-badge role-viewer" style="min-width:80px;text-align:center;">Viewer</span>
|
||
<div class="role-def-text">Read-only access to operations, agents, and logs. Cannot create or modify anything.</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<script>
|
||
function toggleInviteForm() {
|
||
var f = document.getElementById('invite-form');
|
||
var s = document.getElementById('invite-success');
|
||
if (f.style.display === 'none') {
|
||
f.style.display = '';
|
||
s.style.display = 'none';
|
||
document.getElementById('invite-email').focus();
|
||
} else {
|
||
f.style.display = 'none';
|
||
}
|
||
}
|
||
function sendInvite() {
|
||
var email = document.getElementById('invite-email').value.trim();
|
||
if (!email || !email.includes('@')) return;
|
||
document.getElementById('invite-success').style.display = '';
|
||
document.getElementById('invite-email').value = '';
|
||
}
|
||
function updateRole(select, email) {
|
||
// In production: API call to update role
|
||
console.log('Role updated:', email, '->', select.value);
|
||
}
|
||
function removeMember(btn, name) {
|
||
if (!confirm('Remove ' + name + ' from this workspace?')) return;
|
||
btn.closest('.member-row').remove();
|
||
updateMembersCount();
|
||
}
|
||
function revokeInvite(btn) {
|
||
btn.closest('.member-row').remove();
|
||
var pending = document.getElementById('pending-invites');
|
||
if (pending && !pending.querySelector('.member-row')) {
|
||
pending.style.display = 'none';
|
||
}
|
||
}
|
||
function updateMembersCount() {
|
||
var rows = document.querySelectorAll('#members-list .member-row');
|
||
var label = document.getElementById('members-count-label');
|
||
if (label) label.textContent = rows.length + ' member' + (rows.length !== 1 ? 's' : '');
|
||
}
|
||
</script>
|
||
|
||
<!-- ■ SECURITY ■ -->
|
||
<div id="section-security" class="section-anchor">
|
||
<div class="section-card" style="margin-bottom: 20px;">
|
||
<div class="section-card-header">
|
||
<div class="section-card-title">Security</div>
|
||
</div>
|
||
<div class="section-card-body" style="padding-bottom:8px;">
|
||
<div class="field-group">
|
||
<label class="field-label">Current password</label>
|
||
<input class="field-input" id="security-current-password" type="password" placeholder="••••••••" autocomplete="current-password">
|
||
</div>
|
||
<div class="field-row">
|
||
<div class="field-group">
|
||
<label class="field-label">New password</label>
|
||
<input class="field-input" id="security-new-password" type="password" placeholder="min. 12 characters" autocomplete="new-password">
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label">Confirm new password</label>
|
||
<input class="field-input" id="security-confirm-password" type="password" placeholder="••••••••" autocomplete="new-password">
|
||
</div>
|
||
</div>
|
||
<div class="field-hint" id="settings-password-status" style="margin-bottom:12px;"></div>
|
||
<div style="display:flex;justify-content:flex-end;padding-bottom:8px;">
|
||
<button class="btn-primary" id="settings-password-save-btn" type="button">Change password</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="padding: 4px 20px 16px;">
|
||
<div class="settings-section-divider" style="margin-top:0;"></div>
|
||
<div style="font-size:13.5px;font-weight:600;color:var(--text-primary);margin-bottom:12px;">Advanced security</div>
|
||
<div class="field-hint" style="margin-bottom:12px;">Two-factor authentication, passkeys and session management are not implemented yet. The current live security flow is password-based login with HttpOnly session cookies.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="section-card" style="margin-bottom: 20px;">
|
||
<div class="section-card-header">
|
||
<div class="section-card-title">Current session</div>
|
||
</div>
|
||
<div style="padding: 8px 20px 16px;">
|
||
<div class="member-row">
|
||
<div class="member-info">
|
||
<div class="member-name">Browser session — <span style="color:var(--green);font-size:12px;">current</span></div>
|
||
<div class="member-email">Session expires according to server-side auth settings. Use Log out to revoke the current browser session.</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ■ NOTIFICATIONS ■ -->
|
||
<div id="section-notifications" class="section-anchor">
|
||
<div class="section-card" style="margin-bottom: 20px;">
|
||
<div class="section-card-header">
|
||
<div class="section-card-title">Notification preferences</div>
|
||
</div>
|
||
<div style="padding: 8px 20px 16px;">
|
||
<div class="toggle-setting-row">
|
||
<div class="toggle-setting-text">
|
||
<div class="toggle-setting-label">Operation error spike</div>
|
||
<div class="toggle-setting-desc">Alert when error rate exceeds 5% over a 5-minute window.</div>
|
||
</div>
|
||
<div class="toggle-sm on" onclick="this.classList.toggle('on')"></div>
|
||
</div>
|
||
<div class="toggle-setting-row">
|
||
<div class="toggle-setting-text">
|
||
<div class="toggle-setting-label">Upstream latency degradation</div>
|
||
<div class="toggle-setting-desc">Alert when p99 latency exceeds the baseline by 3×.</div>
|
||
</div>
|
||
<div class="toggle-sm on" onclick="this.classList.toggle('on')"></div>
|
||
</div>
|
||
<div class="toggle-setting-row">
|
||
<div class="toggle-setting-text">
|
||
<div class="toggle-setting-label">Quota approaching limit</div>
|
||
<div class="toggle-setting-desc">Email when any operation reaches 80% of its monthly quota.</div>
|
||
</div>
|
||
<div class="toggle-sm on" onclick="this.classList.toggle('on')"></div>
|
||
</div>
|
||
<div class="toggle-setting-row">
|
||
<div class="toggle-setting-text">
|
||
<div class="toggle-setting-label">New team member joined</div>
|
||
<div class="toggle-setting-desc">Notify workspace admins when someone accepts an invite.</div>
|
||
</div>
|
||
<div class="toggle-sm" onclick="this.classList.toggle('on')"></div>
|
||
</div>
|
||
<div class="toggle-setting-row">
|
||
<div class="toggle-setting-text">
|
||
<div class="toggle-setting-label">Weekly usage digest</div>
|
||
<div class="toggle-setting-desc">Email summary of invocations, errors and latency each Monday.</div>
|
||
</div>
|
||
<div class="toggle-sm on" onclick="this.classList.toggle('on')"></div>
|
||
</div>
|
||
<div class="field-hint" style="margin-top:12px;">Notification preferences are local UI placeholders for now and are not synced to the backend yet.</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ■ DANGER ZONE — moved to workspace-setup.html ■ -->
|
||
<div id="section-danger" style="display:none;">
|
||
<div class="section-card" style="border-color: rgba(248,81,73,0.25);">
|
||
<div class="section-card-header" style="border-bottom-color: rgba(248,81,73,0.15);">
|
||
<div class="section-card-title" style="color: var(--red);">Danger zone</div>
|
||
</div>
|
||
<div>
|
||
<div class="danger-zone-action">
|
||
<div class="danger-zone-text">
|
||
<div class="danger-zone-title">Rename workspace</div>
|
||
<div class="danger-zone-desc">Changes the workspace slug used in all API endpoints. Existing API keys will continue to work. All existing tool call references will break.</div>
|
||
</div>
|
||
<button class="btn-danger" type="button">Rename</button>
|
||
</div>
|
||
<div class="danger-zone-action">
|
||
<div class="danger-zone-text">
|
||
<div class="danger-zone-title">Export all data</div>
|
||
<div class="danger-zone-desc">Download a ZIP archive of all operation configs, schemas, mappings and invocation history as JSON. May take a few minutes.</div>
|
||
</div>
|
||
<button class="btn-danger" type="button">Export</button>
|
||
</div>
|
||
<div class="danger-zone-action">
|
||
<div class="danger-zone-text">
|
||
<div class="danger-zone-title">Delete workspace</div>
|
||
<div class="danger-zone-desc">Permanently deletes all operations, keys, logs and settings. This action cannot be undone. You will be logged out immediately.</div>
|
||
</div>
|
||
<button class="btn-danger" type="button" onclick="if(confirm('Delete workspace? This cannot be undone.')) { localStorage.clear(); window.location.href = 'login.html'; }">Delete workspace</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div><!-- /settings-content -->
|
||
</div><!-- /settings-layout -->
|
||
|
||
</div><!-- /page -->
|
||
|
||
<script src="js/nav.js"></script>
|
||
<script src="js/settings.js"></script>
|
||
|
||
</body>
|
||
</html>
|