@agenticmail/enterprise 0.2.2 โ 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +929 -0
- package/dashboards/dotnet/Program.cs +5 -5
- package/dashboards/express/app.js +5 -5
- package/dashboards/go/main.go +8 -8
- package/dashboards/html/index.html +41 -18
- package/dashboards/java/AgenticMailDashboard.java +5 -5
- package/dashboards/php/index.php +8 -8
- package/dashboards/python/app.py +8 -8
- package/dashboards/ruby/app.rb +7 -7
- package/dashboards/shared-styles.css +57 -0
- package/dist/chunk-BE7MXVLA.js +757 -0
- package/dist/chunk-BS2WCSHO.js +48 -0
- package/dist/chunk-FL3VQBGL.js +757 -0
- package/dist/chunk-GXIEEA2T.js +48 -0
- package/dist/chunk-JLSQOQ5L.js +255 -0
- package/dist/chunk-TVF23PUW.js +338 -0
- package/dist/cli.js +305 -140
- package/dist/dashboard/index.html +833 -510
- package/dist/factory-HINWFYZ3.js +9 -0
- package/dist/factory-V37IG5AT.js +9 -0
- package/dist/index.js +18 -12
- package/dist/managed-RZITNPXG.js +14 -0
- package/dist/server-32YYCI3A.js +8 -0
- package/dist/server-H3C6WUOS.js +8 -0
- package/dist/sqlite-VLKVAJA4.js +442 -0
- package/package.json +18 -2
- package/src/cli.ts +15 -251
- package/src/dashboard/index.html +833 -510
- package/src/db/sqlite.ts +4 -1
- package/src/server.ts +1 -1
- package/src/setup/company.ts +64 -0
- package/src/setup/database.ts +119 -0
- package/src/setup/deployment.ts +50 -0
- package/src/setup/domain.ts +46 -0
- package/src/setup/index.ts +82 -0
- package/src/setup/provision.ts +226 -0
- package/test-integration.mjs +383 -0
- package/agenticmail-enterprise.db +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// AgenticMail Enterprise Dashboard โ .NET / C# Edition
|
|
1
|
+
// ๐ AgenticMail Enterprise Dashboard โ .NET / C# Edition
|
|
2
2
|
//
|
|
3
3
|
// Uses .NET 8+ Minimal API. No MVC, no Razor, no extra NuGet packages.
|
|
4
4
|
//
|
|
@@ -60,7 +60,7 @@ string Badge(string status)
|
|
|
60
60
|
var colors = new Dictionary<string, string>
|
|
61
61
|
{
|
|
62
62
|
["active"] = "#22c55e", ["archived"] = "#888", ["suspended"] = "#ef4444",
|
|
63
|
-
["owner"] = "#f59e0b", ["admin"] = "#
|
|
63
|
+
["owner"] = "#f59e0b", ["admin"] = "#e84393", ["member"] = "#888", ["viewer"] = "#555"
|
|
64
64
|
};
|
|
65
65
|
var c = colors.GetValueOrDefault(status, "#888");
|
|
66
66
|
return $"<span style='display:inline-block;padding:2px 10px;border-radius:999px;font-size:11px;font-weight:600;background:{c}20;color:{c}'>{Esc(status)}</span>";
|
|
@@ -68,12 +68,12 @@ string Badge(string status)
|
|
|
68
68
|
|
|
69
69
|
// โโโ CSS & Layout โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
70
70
|
|
|
71
|
-
const string CSS = @"*{box-sizing:border-box;margin:0;padding:0}:root{--bg:#
|
|
71
|
+
const string CSS = @"*{box-sizing:border-box;margin:0;padding:0}:root,[data-theme=light]{--bg:#f8f9fa;--surface:#fff;--border:#dee2e6;--text:#212529;--dim:#495057;--muted:#868e96;--primary:#e84393;--success:#2b8a3e;--danger:#c92a2a;--warning:#e67700;--r:6px;color-scheme:light dark}[data-theme=dark]{--bg:#0f1114;--surface:#16181d;--border:#2c3038;--text:#e1e4e8;--dim:#b0b8c4;--muted:#6b7280;--primary:#f06595;--success:#37b24d;--danger:#f03e3e;--warning:#f08c00}@media(prefers-color-scheme:dark){:root:not([data-theme=light]){--bg:#0f1114;--surface:#16181d;--border:#2c3038;--text:#e1e4e8;--dim:#b0b8c4;--muted:#6b7280;--primary:#f06595;--success:#37b24d;--danger:#f03e3e;--warning:#f08c00}}body{font-family:-apple-system,sans-serif;background:var(--bg);color:var(--text)}.layout{display:flex;min-height:100vh}.sidebar{width:240px;background:var(--surface);border-right:1px solid var(--border);position:fixed;top:0;left:0;bottom:0;display:flex;flex-direction:column}.sh{padding:20px;border-bottom:1px solid var(--border)}.sh h2{font-size:16px}.sh h2 em{font-style:normal;color:var(--primary)}.sh small{font-size:11px;color:var(--muted);display:block;margin-top:2px}.nav{flex:1;padding:8px 0}.ns{font-size:10px;text-transform:uppercase;letter-spacing:0.08em;color:var(--muted);padding:12px 20px 4px}.nav a{display:flex;align-items:center;gap:10px;padding:10px 20px;color:var(--dim);text-decoration:none;font-size:13px}.nav a:hover{color:var(--text);background:rgba(255,255,255,0.03)}.nav a.on{color:var(--primary);background:rgba(232,67,147,0.12);border-right:2px solid var(--primary)}.sf{padding:16px 20px;border-top:1px solid var(--border);font-size:12px}.content{flex:1;margin-left:240px;padding:32px;max-width:1100px}h2.t{font-size:22px;font-weight:700;margin-bottom:4px}.desc{font-size:13px;color:var(--dim);margin-bottom:24px}.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:16px;margin-bottom:24px}.stat{background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:20px}.stat .l{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:0.06em}.stat .v{font-size:30px;font-weight:700;margin-top:4px}.card{background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:20px;margin-bottom:16px}.ct{font-size:13px;color:var(--dim);text-transform:uppercase;letter-spacing:0.05em;font-weight:600;margin-bottom:12px}table{width:100%;border-collapse:collapse;font-size:13px}th{text-align:left;padding:10px 12px;color:var(--muted);font-size:11px;text-transform:uppercase;letter-spacing:0.05em;border-bottom:1px solid var(--border)}td{padding:12px;border-bottom:1px solid var(--border)}.btn{display:inline-flex;align-items:center;padding:8px 16px;border-radius:8px;font-size:13px;font-weight:600;cursor:pointer;border:1px solid var(--border);background:var(--surface);color:var(--text);text-decoration:none}.btn-p{background:var(--primary);border-color:var(--primary);color:#fff}.btn-sm{padding:4px 10px;font-size:12px}.input{width:100%;padding:10px 14px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px}.fg{margin-bottom:14px}.fl{display:block;font-size:12px;color:var(--dim);margin-bottom:4px}.empty{text-align:center;padding:48px 20px;color:var(--muted)}select.input{appearance:auto}";
|
|
72
72
|
|
|
73
73
|
string NavItem(string href, string icon, string label, string page) =>
|
|
74
74
|
$"<a href='{href}' class='{(page == label.ToLower() ? "on" : "")}'>{icon} <span>{label}</span></a>";
|
|
75
75
|
|
|
76
|
-
string Layout(string page, string userName, string userEmail, string content) => $@"<!DOCTYPE html><html><head><meta charset='UTF-8'><meta name='viewport' content='width=device-width,initial-scale=1.0'><title
|
|
76
|
+
string Layout(string page, string userName, string userEmail, string content) => $@"<!DOCTYPE html><html><head><meta charset='UTF-8'><meta name='viewport' content='width=device-width,initial-scale=1.0'><title>๐ AgenticMail Enterprise โ .NET</title><style>{CSS}</style></head>
|
|
77
77
|
<body><div class='layout'>
|
|
78
78
|
<div class='sidebar'><div class='sh'><h2>๐ข <em>Agentic</em>Mail</h2><small>Enterprise ยท .NET</small></div>
|
|
79
79
|
<div class='nav'><div class='ns'>Overview</div>{NavItem("/", "๐", "Dashboard", page)}<div class='ns'>Manage</div>{NavItem("/agents", "๐ค", "Agents", page)}{NavItem("/users", "๐ฅ", "Users", page)}{NavItem("/api-keys", "๐", "API Keys", page)}<div class='ns'>System</div>{NavItem("/audit", "๐", "Audit", page)}{NavItem("/settings", "โ๏ธ", "Settings", page)}</div>
|
|
@@ -254,7 +254,7 @@ app.MapGet("/settings", async (HttpContext ctx) =>
|
|
|
254
254
|
var port = Environment.GetEnvironmentVariable("PORT") ?? "5002";
|
|
255
255
|
app.Urls.Add($"http://localhost:{port}");
|
|
256
256
|
|
|
257
|
-
Console.WriteLine($"\n๐ข AgenticMail Enterprise Dashboard (.NET)");
|
|
257
|
+
Console.WriteLine($"\n๐ข ๐ AgenticMail Enterprise Dashboard (.NET)");
|
|
258
258
|
Console.WriteLine($" API: {API_URL}");
|
|
259
259
|
Console.WriteLine($" Dashboard: http://localhost:{port}\n");
|
|
260
260
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* AgenticMail Enterprise Dashboard โ Express.js Edition
|
|
2
|
+
* ๐ AgenticMail Enterprise Dashboard โ Express.js Edition
|
|
3
3
|
*
|
|
4
4
|
* Setup:
|
|
5
5
|
* npm install express express-session
|
|
@@ -48,8 +48,8 @@ function page(p, user, content, flash) {
|
|
|
48
48
|
const nav = (href, icon, label, key) =>
|
|
49
49
|
`<a href="${href}" class="${p === key ? 'on' : ''}">${icon} <span>${label}</span></a>`;
|
|
50
50
|
const flashHtml = flash ? `<div style="padding:12px 16px;border-radius:8px;margin-bottom:16px;font-size:13px;background:rgba(34,197,94,0.1);border:1px solid #22c55e;color:#22c55e">${flash}</div>` : '';
|
|
51
|
-
return `<!DOCTYPE html><html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0"><title
|
|
52
|
-
<style>*{box-sizing:border-box;margin:0;padding:0}:root{--bg:#
|
|
51
|
+
return `<!DOCTYPE html><html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0"><title>๐ AgenticMail Enterprise โ Express</title>
|
|
52
|
+
<style>*{box-sizing:border-box;margin:0;padding:0}:root,[data-theme=light]{--bg:#f8f9fa;--surface:#fff;--border:#dee2e6;--text:#212529;--dim:#495057;--muted:#868e96;--primary:#e84393;--success:#2b8a3e;--danger:#c92a2a;--warning:#e67700;--r:6px;color-scheme:light dark}[data-theme=dark]{--bg:#0f1114;--surface:#16181d;--border:#2c3038;--text:#e1e4e8;--dim:#b0b8c4;--muted:#6b7280;--primary:#f06595;--success:#37b24d;--danger:#f03e3e;--warning:#f08c00}@media(prefers-color-scheme:dark){:root:not([data-theme=light]){--bg:#0f1114;--surface:#16181d;--border:#2c3038;--text:#e1e4e8;--dim:#b0b8c4;--muted:#6b7280;--primary:#f06595;--success:#37b24d;--danger:#f03e3e;--warning:#f08c00}}body{font-family:-apple-system,sans-serif;background:var(--bg);color:var(--text)}.layout{display:flex;min-height:100vh}.sidebar{width:240px;background:var(--surface);border-right:1px solid var(--border);position:fixed;top:0;left:0;bottom:0;display:flex;flex-direction:column}.sh{padding:20px;border-bottom:1px solid var(--border)}.sh h2{font-size:16px}.sh h2 em{font-style:normal;color:var(--primary)}.sh small{font-size:11px;color:var(--muted);display:block;margin-top:2px}.nav{flex:1;padding:8px 0}.ns{font-size:10px;text-transform:uppercase;letter-spacing:0.08em;color:var(--muted);padding:12px 20px 4px}.nav a{display:flex;align-items:center;gap:10px;padding:10px 20px;color:var(--dim);text-decoration:none;font-size:13px}.nav a:hover{color:var(--text);background:rgba(255,255,255,0.03)}.nav a.on{color:var(--primary);background:rgba(232,67,147,0.12);border-right:2px solid var(--primary)}.sf{padding:16px 20px;border-top:1px solid var(--border);font-size:12px}.content{flex:1;margin-left:240px;padding:32px;max-width:1100px}h2.t{font-size:22px;font-weight:700;margin-bottom:4px}.desc{font-size:13px;color:var(--dim);margin-bottom:24px}.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:16px;margin-bottom:24px}.stat{background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:20px}.stat .l{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:0.06em}.stat .v{font-size:30px;font-weight:700;margin-top:4px}.card{background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:20px;margin-bottom:16px}.ct{font-size:13px;color:var(--dim);text-transform:uppercase;letter-spacing:0.05em;font-weight:600;margin-bottom:12px}table{width:100%;border-collapse:collapse;font-size:13px}th{text-align:left;padding:10px 12px;color:var(--muted);font-size:11px;text-transform:uppercase;letter-spacing:0.05em;border-bottom:1px solid var(--border)}td{padding:12px;border-bottom:1px solid var(--border)}.badge{display:inline-block;padding:2px 10px;border-radius:999px;font-size:11px;font-weight:600}.b-a{background:rgba(34,197,94,0.12);color:var(--success)}.b-r{background:rgba(136,136,160,0.1);color:var(--dim)}.empty{text-align:center;padding:48px 20px;color:var(--muted)}.btn{display:inline-flex;align-items:center;padding:8px 16px;border-radius:8px;font-size:13px;font-weight:600;cursor:pointer;border:1px solid var(--border);background:var(--surface);color:var(--text);text-decoration:none}.btn-p{background:var(--primary);border-color:var(--primary);color:#fff}.input{width:100%;padding:10px 14px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px}.fg{margin-bottom:14px}.fl{display:block;font-size:12px;color:var(--dim);margin-bottom:4px}</style></head>
|
|
53
53
|
<body><div class="layout">
|
|
54
54
|
<div class="sidebar"><div class="sh"><h2>๐ข <em>Agentic</em>Mail</h2><small>Enterprise ยท Express</small></div>
|
|
55
55
|
<div class="nav"><div class="ns">Overview</div>${nav('/', '๐', 'Dashboard', 'dashboard')}
|
|
@@ -68,7 +68,7 @@ function badge(status) {
|
|
|
68
68
|
// โโโ Routes โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
69
69
|
|
|
70
70
|
app.get('/login', (req, res) => {
|
|
71
|
-
res.send(`<!DOCTYPE html><html><head><meta charset="UTF-8"><title>AgenticMail</title><style>*{box-sizing:border-box;margin:0;padding:0}body{font-family:-apple-system,sans-serif;background:#
|
|
71
|
+
res.send(`<!DOCTYPE html><html><head><meta charset="UTF-8"><title>AgenticMail</title><style>*{box-sizing:border-box;margin:0;padding:0}body{font-family:-apple-system,sans-serif;background:#f8f9fa;color:#212529;display:flex;align-items:center;justify-content:center;min-height:100vh}.box{width:380px}h1{text-align:center;font-size:22px;margin-bottom:4px}h1 em{font-style:normal;color:#e84393}.sub{text-align:center;color:#868e96;font-size:13px;margin-bottom:32px}.fg{margin-bottom:14px}.fl{display:block;font-size:12px;color:#868e96;margin-bottom:4px}.input{width:100%;padding:10px 14px;background:#ffffff;border:1px solid #dee2e6;border-radius:8px;color:#212529;font-size:14px;outline:none}.input:focus{border-color:#e84393}.btn{width:100%;padding:10px;background:#e84393;border:none;border-radius:8px;color:#fff;font-size:14px;font-weight:600;cursor:pointer}</style></head><body><div class="box"><h1>๐ข <em>AgenticMail</em> Enterprise</h1><p class="sub">Sign in ยท Express Dashboard</p><form method="POST" action="/login"><div class="fg"><label class="fl">Email</label><input class="input" type="email" name="email" required></div><div class="fg"><label class="fl">Password</label><input class="input" type="password" name="password" required></div><button class="btn" type="submit">Sign In</button></form></div></body></html>`);
|
|
72
72
|
});
|
|
73
73
|
|
|
74
74
|
app.post('/login', async (req, res) => {
|
|
@@ -140,7 +140,7 @@ app.get('/settings', requireAuth, async (req, res) => {
|
|
|
140
140
|
|
|
141
141
|
const PORT = process.env.PORT || 5001;
|
|
142
142
|
app.listen(PORT, () => {
|
|
143
|
-
console.log(`\n๐ข AgenticMail Enterprise Dashboard (Express.js)`);
|
|
143
|
+
console.log(`\n๐ข ๐ AgenticMail Enterprise Dashboard (Express.js)`);
|
|
144
144
|
console.log(` API: ${API_URL}`);
|
|
145
145
|
console.log(` Dashboard: http://localhost:${PORT}\n`);
|
|
146
146
|
});
|
package/dashboards/go/main.go
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// AgenticMail Enterprise Dashboard โ Go Edition
|
|
1
|
+
// ๐ AgenticMail Enterprise Dashboard โ Go Edition
|
|
2
2
|
//
|
|
3
3
|
// ZERO dependencies beyond the standard library. No frameworks.
|
|
4
4
|
//
|
|
@@ -107,7 +107,7 @@ func esc(s interface{}) string {
|
|
|
107
107
|
func badge(status string) string {
|
|
108
108
|
colors := map[string]string{
|
|
109
109
|
"active": "#22c55e", "archived": "#888", "suspended": "#ef4444",
|
|
110
|
-
"owner": "#f59e0b", "admin": "#
|
|
110
|
+
"owner": "#f59e0b", "admin": "#e84393", "member": "#888", "viewer": "#555",
|
|
111
111
|
}
|
|
112
112
|
c := colors[status]
|
|
113
113
|
if c == "" {
|
|
@@ -154,8 +154,8 @@ func layout(page string, user map[string]interface{}, content string) string {
|
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
return fmt.Sprintf(`<!DOCTYPE html><html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
|
|
157
|
-
<title
|
|
158
|
-
<style>*{box-sizing:border-box;margin:0;padding:0}:root{--bg:#
|
|
157
|
+
<title>๐ AgenticMail Enterprise โ Go</title>
|
|
158
|
+
<style>*{box-sizing:border-box;margin:0;padding:0}:root,[data-theme=light]{--bg:#f8f9fa;--surface:#fff;--border:#dee2e6;--text:#212529;--dim:#495057;--muted:#868e96;--primary:#e84393;--success:#2b8a3e;--danger:#c92a2a;--warning:#e67700;--r:6px;color-scheme:light dark}[data-theme=dark]{--bg:#0f1114;--surface:#16181d;--border:#2c3038;--text:#e1e4e8;--dim:#b0b8c4;--muted:#6b7280;--primary:#f06595;--success:#37b24d;--danger:#f03e3e;--warning:#f08c00}@media(prefers-color-scheme:dark){:root:not([data-theme=light]){--bg:#0f1114;--surface:#16181d;--border:#2c3038;--text:#e1e4e8;--dim:#b0b8c4;--muted:#6b7280;--primary:#f06595;--success:#37b24d;--danger:#f03e3e;--warning:#f08c00}}body{font-family:-apple-system,sans-serif;background:var(--bg);color:var(--text)}.layout{display:flex;min-height:100vh}.sidebar{width:240px;background:var(--surface);border-right:1px solid var(--border);position:fixed;top:0;left:0;bottom:0;display:flex;flex-direction:column}.sh{padding:20px;border-bottom:1px solid var(--border)}.sh h2{font-size:16px}.sh h2 em{font-style:normal;color:var(--primary)}.sh small{font-size:11px;color:var(--muted);display:block;margin-top:2px}.nav{flex:1;padding:8px 0}.ns{font-size:10px;text-transform:uppercase;letter-spacing:0.08em;color:var(--muted);padding:12px 20px 4px}.nav a{display:flex;align-items:center;gap:10px;padding:10px 20px;color:var(--dim);text-decoration:none;font-size:13px}.nav a:hover{color:var(--text);background:rgba(255,255,255,0.03)}.nav a.on{color:var(--primary);background:rgba(232,67,147,0.12);border-right:2px solid var(--primary)}.sf{padding:16px 20px;border-top:1px solid var(--border);font-size:12px}.content{flex:1;margin-left:240px;padding:32px;max-width:1100px}h2.t{font-size:22px;font-weight:700;margin-bottom:4px}.desc{font-size:13px;color:var(--dim);margin-bottom:24px}.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:16px;margin-bottom:24px}.stat{background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:20px}.stat .l{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:0.06em}.stat .v{font-size:30px;font-weight:700;margin-top:4px}.card{background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:20px;margin-bottom:16px}.ct{font-size:13px;color:var(--dim);text-transform:uppercase;letter-spacing:0.05em;font-weight:600;margin-bottom:12px}table{width:100%%;border-collapse:collapse;font-size:13px}th{text-align:left;padding:10px 12px;color:var(--muted);font-size:11px;text-transform:uppercase;letter-spacing:0.05em;border-bottom:1px solid var(--border)}td{padding:12px;border-bottom:1px solid var(--border)}tr:hover td{background:rgba(255,255,255,0.015)}.btn{display:inline-flex;align-items:center;padding:8px 16px;border-radius:8px;font-size:13px;font-weight:600;cursor:pointer;border:1px solid var(--border);background:var(--surface);color:var(--text);text-decoration:none}.btn:hover{background:rgba(255,255,255,0.05)}.btn-p{background:var(--primary);border-color:var(--primary);color:#fff}.btn-d{color:var(--danger);border-color:var(--danger)}.btn-sm{padding:4px 10px;font-size:12px}.input{width:100%%;padding:10px 14px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px}.fg{margin-bottom:14px}.fl{display:block;font-size:12px;color:var(--dim);margin-bottom:4px}.empty{text-align:center;padding:48px 20px;color:var(--muted)}.empty-i{font-size:36px;margin-bottom:10px}select.input{appearance:auto}@media(max-width:768px){.sidebar{width:56px}.sh h2,.sh small,.nav a span,.ns,.sf{display:none}.nav a{justify-content:center;padding:14px 0;font-size:18px}.content{margin-left:56px;padding:16px}}</style></head>
|
|
159
159
|
<body><div class="layout">
|
|
160
160
|
<div class="sidebar"><div class="sh"><h2>๐ข <em>Agentic</em>Mail</h2><small>Enterprise ยท Go</small></div>
|
|
161
161
|
<div class="nav"><div class="ns">Overview</div>%s
|
|
@@ -173,8 +173,8 @@ func layout(page string, user map[string]interface{}, content string) string {
|
|
|
173
173
|
}
|
|
174
174
|
|
|
175
175
|
func loginPage() string {
|
|
176
|
-
return `<!DOCTYPE html><html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0"><title
|
|
177
|
-
<style>*{box-sizing:border-box;margin:0;padding:0}body{font-family:-apple-system,sans-serif;background:#
|
|
176
|
+
return `<!DOCTYPE html><html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0"><title>๐ AgenticMail Enterprise</title>
|
|
177
|
+
<style>*{box-sizing:border-box;margin:0;padding:0}body{font-family:-apple-system,sans-serif;background:#f8f9fa;color:#212529;display:flex;align-items:center;justify-content:center;min-height:100vh}.box{width:380px}h1{text-align:center;font-size:22px;margin-bottom:4px}h1 em{font-style:normal;color:#e84393}.sub{text-align:center;color:#868e96;font-size:13px;margin-bottom:32px}.fg{margin-bottom:14px}.fl{display:block;font-size:12px;color:#868e96;margin-bottom:4px}.input{width:100%;padding:10px 14px;background:#ffffff;border:1px solid #dee2e6;border-radius:8px;color:#212529;font-size:14px;outline:none}.input:focus{border-color:#e84393}.btn{width:100%;padding:10px;background:#e84393;border:none;border-radius:8px;color:#fff;font-size:14px;font-weight:600;cursor:pointer}.btn:hover{background:#f06595}</style></head>
|
|
178
178
|
<body><div class="box"><h1>๐ข <em>AgenticMail</em> Enterprise</h1><p class="sub">Sign in ยท Go Dashboard</p>
|
|
179
179
|
<form method="POST" action="/login"><div class="fg"><label class="fl">Email</label><input class="input" type="email" name="email" required autofocus></div>
|
|
180
180
|
<div class="fg"><label class="fl">Password</label><input class="input" type="password" name="password" required></div>
|
|
@@ -209,7 +209,7 @@ func handleLogin(w http.ResponseWriter, r *http.Request) {
|
|
|
209
209
|
errMsg = fmt.Sprintf("%v", data["error"])
|
|
210
210
|
}
|
|
211
211
|
w.Header().Set("Content-Type", "text/html")
|
|
212
|
-
fmt.Fprintf(w, `<html><body style="background:#
|
|
212
|
+
fmt.Fprintf(w, `<html><body style="background:#f8f9fa;color:#ef4444;font-family:sans-serif;display:flex;align-items:center;justify-content:center;min-height:100vh"><div>%s <a href="/login" style="color:#e84393">Try again</a></div></body></html>`, esc(errMsg))
|
|
213
213
|
return
|
|
214
214
|
}
|
|
215
215
|
user, _ := data["user"].(map[string]interface{})
|
|
@@ -505,7 +505,7 @@ func main() {
|
|
|
505
505
|
port = "8080"
|
|
506
506
|
}
|
|
507
507
|
|
|
508
|
-
fmt.Printf("\n๐ข AgenticMail Enterprise Dashboard (Go)\n")
|
|
508
|
+
fmt.Printf("\n๐ข ๐ AgenticMail Enterprise Dashboard (Go)\n")
|
|
509
509
|
fmt.Printf(" API: %s\n", apiURL)
|
|
510
510
|
fmt.Printf(" Dashboard: http://localhost:%s\n\n", port)
|
|
511
511
|
|
|
@@ -3,16 +3,16 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title
|
|
6
|
+
<title>๐ AgenticMail Enterprise Dashboard</title>
|
|
7
7
|
<style>
|
|
8
8
|
/*
|
|
9
|
-
* AgenticMail Enterprise โ Pure HTML Dashboard
|
|
9
|
+
* ๐ AgenticMail Enterprise โ Pure HTML Dashboard
|
|
10
10
|
*
|
|
11
11
|
* ZERO dependencies. No Node.js, no npm, no React, no build tools.
|
|
12
12
|
* Just open this file in any browser.
|
|
13
13
|
*
|
|
14
14
|
* Setup:
|
|
15
|
-
* 1. Edit the API_URL below to point to your AgenticMail Enterprise server
|
|
15
|
+
* 1. Edit the API_URL below to point to your ๐ AgenticMail Enterprise server
|
|
16
16
|
* 2. Open this file in any browser (or host it on any web server)
|
|
17
17
|
* 3. Login with your admin credentials
|
|
18
18
|
*
|
|
@@ -20,19 +20,42 @@
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
23
|
-
:root {
|
|
24
|
-
--bg: #
|
|
25
|
-
--border: #
|
|
26
|
-
--text: #
|
|
27
|
-
--primary: #
|
|
28
|
-
--success: #
|
|
29
|
-
--warning: #
|
|
30
|
-
--danger: #
|
|
31
|
-
--radius:
|
|
23
|
+
:root, [data-theme="light"] {
|
|
24
|
+
--bg: #f8f9fa; --surface: #ffffff; --surface-hover: #f1f3f5;
|
|
25
|
+
--border: #dee2e6; --border-hover: #ced4da;
|
|
26
|
+
--text: #212529; --text-dim: #495057; --text-muted: #868e96;
|
|
27
|
+
--primary: #e84393; --primary-hover: #d63384; --primary-bg: rgba(232,67,147,0.08);
|
|
28
|
+
--success: #2b8a3e; --success-bg: rgba(43,138,62,0.08);
|
|
29
|
+
--warning: #e67700; --warning-bg: rgba(230,119,0,0.08);
|
|
30
|
+
--danger: #c92a2a; --danger-bg: rgba(201,42,42,0.08);
|
|
31
|
+
--radius: 6px; --radius-lg: 10px;
|
|
32
|
+
--shadow: 0 1px 3px rgba(0,0,0,0.08);
|
|
33
|
+
--font: -apple-system, BlinkMacSystemFont, 'Inter', 'Segoe UI', system-ui, sans-serif;
|
|
34
|
+
color-scheme: light dark;
|
|
35
|
+
}
|
|
36
|
+
[data-theme="dark"] {
|
|
37
|
+
--bg: #0f1114; --surface: #16181d; --surface-hover: #1c1f26;
|
|
38
|
+
--border: #2c3038; --border-hover: #3b414c;
|
|
39
|
+
--text: #e1e4e8; --text-dim: #b0b8c4; --text-muted: #6b7280;
|
|
40
|
+
--primary: #f06595; --primary-hover: #f783ac; --primary-bg: rgba(240,101,149,0.1);
|
|
41
|
+
--success: #37b24d; --success-bg: rgba(55,178,77,0.1);
|
|
42
|
+
--warning: #f08c00; --warning-bg: rgba(240,140,0,0.1);
|
|
43
|
+
--danger: #f03e3e; --danger-bg: rgba(240,62,62,0.1);
|
|
32
44
|
--shadow: 0 1px 3px rgba(0,0,0,0.3);
|
|
33
|
-
--font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
34
45
|
}
|
|
35
|
-
|
|
46
|
+
@media (prefers-color-scheme: dark) {
|
|
47
|
+
:root:not([data-theme="light"]) {
|
|
48
|
+
--bg: #0f1114; --surface: #16181d; --surface-hover: #1c1f26;
|
|
49
|
+
--border: #2c3038; --border-hover: #3b414c;
|
|
50
|
+
--text: #e1e4e8; --text-dim: #b0b8c4; --text-muted: #6b7280;
|
|
51
|
+
--primary: #f06595; --primary-hover: #f783ac; --primary-bg: rgba(240,101,149,0.1);
|
|
52
|
+
--success: #37b24d; --success-bg: rgba(55,178,77,0.1);
|
|
53
|
+
--warning: #f08c00; --warning-bg: rgba(240,140,0,0.1);
|
|
54
|
+
--danger: #f03e3e; --danger-bg: rgba(240,62,62,0.1);
|
|
55
|
+
--shadow: 0 1px 3px rgba(0,0,0,0.3);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
body { font-family: var(--font); background: var(--bg); color: var(--text); line-height: 1.5; min-height: 100vh; -webkit-font-smoothing: antialiased; }
|
|
36
59
|
|
|
37
60
|
/* โโโ Setup Banner โโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
|
38
61
|
#setup-banner { display: none; background: var(--warning-bg); border: 1px solid var(--warning); border-radius: var(--radius); padding: 16px 20px; margin: 20px; }
|
|
@@ -134,14 +157,14 @@
|
|
|
134
157
|
CONFIGURATION โ Edit this ONE line to get started
|
|
135
158
|
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ -->
|
|
136
159
|
<script>
|
|
137
|
-
// ๐ Change this to your AgenticMail Enterprise server URL
|
|
160
|
+
// ๐ Change this to your ๐ AgenticMail Enterprise server URL
|
|
138
161
|
var API_URL = 'http://localhost:3000';
|
|
139
162
|
</script>
|
|
140
163
|
|
|
141
164
|
<!-- Setup banner (shown if API_URL is still localhost) -->
|
|
142
165
|
<div id="setup-banner">
|
|
143
166
|
<h3>โก Quick Setup</h3>
|
|
144
|
-
<p style="color:var(--text-dim);font-size:13px;margin-bottom:12px;">Enter your AgenticMail Enterprise server URL to get started:</p>
|
|
167
|
+
<p style="color:var(--text-dim);font-size:13px;margin-bottom:12px;">Enter your ๐ AgenticMail Enterprise server URL to get started:</p>
|
|
145
168
|
<div>
|
|
146
169
|
<input type="text" id="setup-url" placeholder="https://your-company.agenticmail.cloud" value="">
|
|
147
170
|
<button onclick="saveApiUrl()">Connect</button>
|
|
@@ -256,7 +279,7 @@
|
|
|
256
279
|
|
|
257
280
|
<script>
|
|
258
281
|
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
259
|
-
// AgenticMail Enterprise โ Pure JavaScript Dashboard
|
|
282
|
+
// ๐ AgenticMail Enterprise โ Pure JavaScript Dashboard
|
|
260
283
|
// No frameworks, no build tools, no dependencies.
|
|
261
284
|
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
262
285
|
|
|
@@ -501,7 +524,7 @@ function renderSettings() {
|
|
|
501
524
|
'<form onsubmit="saveSettings(event)" style="display:grid;grid-template-columns:1fr 1fr;gap:14px">' +
|
|
502
525
|
'<div class="form-group"><label class="form-label">Organization Name</label><input class="input" id="set-name" value="' + esc(s.name || '') + '"></div>' +
|
|
503
526
|
'<div class="form-group"><label class="form-label">Domain</label><input class="input" id="set-domain" value="' + esc(s.domain || '') + '" placeholder="agents.acme.com"></div>' +
|
|
504
|
-
'<div class="form-group"><label class="form-label">Primary Color</label><input class="input" type="color" id="set-color" value="' + (s.primaryColor || '#
|
|
527
|
+
'<div class="form-group"><label class="form-label">Primary Color</label><input class="input" type="color" id="set-color" value="' + (s.primaryColor || '#e84393') + '" style="height:38px;padding:4px"></div>' +
|
|
505
528
|
'<div class="form-group"><label class="form-label">Logo URL</label><input class="input" id="set-logo" value="' + esc(s.logoUrl || '') + '" placeholder="https://..."></div>' +
|
|
506
529
|
'<div style="grid-column:span 2"><button class="btn btn-primary" type="submit" style="width:auto">Save Settings</button></div></form></div>' +
|
|
507
530
|
'<div class="card"><div class="card-title">Plan</div>' +
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* AgenticMail Enterprise Dashboard โ Java Edition
|
|
2
|
+
* ๐ AgenticMail Enterprise Dashboard โ Java Edition
|
|
3
3
|
*
|
|
4
4
|
* ZERO dependencies. Uses only JDK built-in classes (Java 11+).
|
|
5
5
|
* No Spring, no Maven, no Gradle needed.
|
|
@@ -161,7 +161,7 @@ public class AgenticMailDashboard {
|
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
static String badge(String status) {
|
|
164
|
-
Map<String, String> colors = Map.of("active","#22c55e","archived","#888","suspended","#ef4444","owner","#f59e0b","admin","#
|
|
164
|
+
Map<String, String> colors = Map.of("active","#22c55e","archived","#888","suspended","#ef4444","owner","#f59e0b","admin","#e84393","member","#888");
|
|
165
165
|
String c = colors.getOrDefault(status, "#888");
|
|
166
166
|
return String.format("<span style='display:inline-block;padding:2px 10px;border-radius:999px;font-size:11px;font-weight:600;background:%s20;color:%s'>%s</span>", c, c, esc(status));
|
|
167
167
|
}
|
|
@@ -233,7 +233,7 @@ public class AgenticMailDashboard {
|
|
|
233
233
|
|
|
234
234
|
// โโโ CSS โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
235
235
|
|
|
236
|
-
static final String CSS = "*{box-sizing:border-box;margin:0;padding:0}:root{--bg:#
|
|
236
|
+
static final String CSS = "*{box-sizing:border-box;margin:0;padding:0}:root,[data-theme=light]{--bg:#f8f9fa;--surface:#fff;--border:#dee2e6;--text:#212529;--dim:#495057;--muted:#868e96;--primary:#e84393;--success:#2b8a3e;--danger:#c92a2a;--warning:#e67700;--r:6px;color-scheme:light dark}[data-theme=dark]{--bg:#0f1114;--surface:#16181d;--border:#2c3038;--text:#e1e4e8;--dim:#b0b8c4;--muted:#6b7280;--primary:#f06595;--success:#37b24d;--danger:#f03e3e;--warning:#f08c00}@media(prefers-color-scheme:dark){:root:not([data-theme=light]){--bg:#0f1114;--surface:#16181d;--border:#2c3038;--text:#e1e4e8;--dim:#b0b8c4;--muted:#6b7280;--primary:#f06595;--success:#37b24d;--danger:#f03e3e;--warning:#f08c00}}body{font-family:-apple-system,sans-serif;background:var(--bg);color:var(--text)}.layout{display:flex;min-height:100vh}.sidebar{width:240px;background:var(--surface);border-right:1px solid var(--border);position:fixed;top:0;left:0;bottom:0;display:flex;flex-direction:column}.sh{padding:20px;border-bottom:1px solid var(--border)}.sh h2{font-size:16px}.sh h2 em{font-style:normal;color:var(--primary)}.sh small{font-size:11px;color:var(--muted);display:block;margin-top:2px}.nav{flex:1;padding:8px 0}.ns{font-size:10px;text-transform:uppercase;letter-spacing:0.08em;color:var(--muted);padding:12px 20px 4px}.nav a{display:flex;align-items:center;gap:10px;padding:10px 20px;color:var(--dim);text-decoration:none;font-size:13px}.nav a:hover{color:var(--text);background:rgba(255,255,255,0.03)}.nav a.on{color:var(--primary);background:rgba(232,67,147,0.12);border-right:2px solid var(--primary)}.sf{padding:16px 20px;border-top:1px solid var(--border);font-size:12px}.content{flex:1;margin-left:240px;padding:32px;max-width:1100px}h2.t{font-size:22px;font-weight:700;margin-bottom:4px}.desc{font-size:13px;color:var(--dim);margin-bottom:24px}.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:16px;margin-bottom:24px}.stat{background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:20px}.stat .l{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:0.06em}.stat .v{font-size:30px;font-weight:700;margin-top:4px}.card{background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:20px;margin-bottom:16px}.ct{font-size:13px;color:var(--dim);text-transform:uppercase;letter-spacing:0.05em;font-weight:600;margin-bottom:12px}table{width:100%;border-collapse:collapse;font-size:13px}th{text-align:left;padding:10px 12px;color:var(--muted);font-size:11px;text-transform:uppercase;letter-spacing:0.05em;border-bottom:1px solid var(--border)}td{padding:12px;border-bottom:1px solid var(--border)}.btn{display:inline-flex;align-items:center;padding:8px 16px;border-radius:8px;font-size:13px;font-weight:600;cursor:pointer;border:1px solid var(--border);background:var(--surface);color:var(--text);text-decoration:none}.btn-p{background:var(--primary);border-color:var(--primary);color:#fff}.btn-d{color:var(--danger);border-color:var(--danger)}.btn-sm{padding:4px 10px;font-size:12px}.input{width:100%;padding:10px 14px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px}.fg{margin-bottom:14px}.fl{display:block;font-size:12px;color:var(--dim);margin-bottom:4px}.empty{text-align:center;padding:48px 20px;color:var(--muted)}.empty-i{font-size:36px;margin-bottom:10px}select.input{appearance:auto}";
|
|
237
237
|
|
|
238
238
|
static String navItem(String href, String icon, String label, String active) {
|
|
239
239
|
String cls = active.equals(label.toLowerCase()) ? " on" : "";
|
|
@@ -243,7 +243,7 @@ public class AgenticMailDashboard {
|
|
|
243
243
|
static String layout(String page, Map<String, Object> user, String content) {
|
|
244
244
|
String userName = user != null ? esc(user.get("name")) : "";
|
|
245
245
|
String userEmail = user != null ? esc(user.get("email")) : "";
|
|
246
|
-
return String.format("<!DOCTYPE html><html><head><meta charset='UTF-8'><meta name='viewport' content='width=device-width,initial-scale=1.0'><title
|
|
246
|
+
return String.format("<!DOCTYPE html><html><head><meta charset='UTF-8'><meta name='viewport' content='width=device-width,initial-scale=1.0'><title>๐ AgenticMail Enterprise โ Java</title><style>%s</style></head><body><div class='layout'>" +
|
|
247
247
|
"<div class='sidebar'><div class='sh'><h2>๐ข <em>Agentic</em>Mail</h2><small>Enterprise ยท Java</small></div>" +
|
|
248
248
|
"<div class='nav'><div class='ns'>Overview</div>%s<div class='ns'>Manage</div>%s%s%s<div class='ns'>System</div>%s%s</div>" +
|
|
249
249
|
"<div class='sf'><div style='color:var(--dim)'>%s</div><div style='color:var(--muted);font-size:11px'>%s</div><a href='/logout' style='color:var(--muted);font-size:11px;margin-top:6px;display:inline-block'>Sign out</a></div></div>" +
|
|
@@ -369,7 +369,7 @@ public class AgenticMailDashboard {
|
|
|
369
369
|
server.createContext("/", ex -> { if (getToken(ex)==null) { redirect(ex,"/login"); return; } try { handleDashboard(ex); } catch (Exception e) { respond(ex, 500, e.getMessage()); } });
|
|
370
370
|
|
|
371
371
|
server.start();
|
|
372
|
-
System.out.printf("%n๐ข AgenticMail Enterprise Dashboard (Java)%n");
|
|
372
|
+
System.out.printf("%n๐ข ๐ AgenticMail Enterprise Dashboard (Java)%n");
|
|
373
373
|
System.out.printf(" API: %s%n", API_URL);
|
|
374
374
|
System.out.printf(" Dashboard: http://localhost:%d%n%n", port);
|
|
375
375
|
}
|
package/dashboards/php/index.php
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<?php
|
|
2
2
|
/**
|
|
3
|
-
* AgenticMail Enterprise Dashboard โ PHP Edition
|
|
3
|
+
* ๐ AgenticMail Enterprise Dashboard โ PHP Edition
|
|
4
4
|
*
|
|
5
5
|
* ZERO dependencies. No Composer, no Laravel, no framework.
|
|
6
6
|
* Just PHP 7.4+ and a web server.
|
|
@@ -110,7 +110,7 @@ if ($action === 'save_settings' && $token) {
|
|
|
110
110
|
$result = am_api('/api/settings', 'PATCH', [
|
|
111
111
|
'name' => $_POST['name'] ?? '',
|
|
112
112
|
'domain' => $_POST['domain'] ?? '',
|
|
113
|
-
'primaryColor' => $_POST['primaryColor'] ?? '#
|
|
113
|
+
'primaryColor' => $_POST['primaryColor'] ?? '#e84393',
|
|
114
114
|
]);
|
|
115
115
|
$success = isset($result['error']) ? $result['error'] : 'Settings saved!';
|
|
116
116
|
}
|
|
@@ -140,7 +140,7 @@ if ($token) {
|
|
|
140
140
|
|
|
141
141
|
function e(string $s): string { return htmlspecialchars($s, ENT_QUOTES, 'UTF-8'); }
|
|
142
142
|
function badge(string $status): string {
|
|
143
|
-
$colors = ['active'=>'#22c55e','archived'=>'#888','suspended'=>'#ef4444','owner'=>'#f59e0b','admin'=>'#
|
|
143
|
+
$colors = ['active'=>'#22c55e','archived'=>'#888','suspended'=>'#ef4444','owner'=>'#f59e0b','admin'=>'#e84393','member'=>'#888','viewer'=>'#555'];
|
|
144
144
|
$c = $colors[$status] ?? '#888';
|
|
145
145
|
return "<span style='display:inline-block;padding:2px 10px;border-radius:999px;font-size:11px;font-weight:600;background:{$c}20;color:$c'>$status</span>";
|
|
146
146
|
}
|
|
@@ -150,10 +150,10 @@ function badge(string $status): string {
|
|
|
150
150
|
<head>
|
|
151
151
|
<meta charset="UTF-8">
|
|
152
152
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
153
|
-
<title
|
|
153
|
+
<title>๐ AgenticMail Enterprise โ PHP Dashboard</title>
|
|
154
154
|
<style>
|
|
155
155
|
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
156
|
-
:root { --bg:#
|
|
156
|
+
:root,[data-theme="light"] { --bg:#f8f9fa; --surface:#fff; --border:#dee2e6; --text:#212529; --dim:#495057; --muted:#868e96; --primary:#e84393; --success:#2b8a3e; --danger:#c92a2a; --warning:#e67700; --r:6px; color-scheme:light dark; } [data-theme="dark"] { --bg:#0f1114; --surface:#16181d; --border:#2c3038; --text:#e1e4e8; --dim:#b0b8c4; --muted:#6b7280; --primary:#f06595; --success:#37b24d; --danger:#f03e3e; --warning:#f08c00; } @media(prefers-color-scheme:dark){ :root:not([data-theme="light"]){ --bg:#0f1114; --surface:#16181d; --border:#2c3038; --text:#e1e4e8; --dim:#b0b8c4; --muted:#6b7280; --primary:#f06595; --success:#37b24d; --danger:#f03e3e; --warning:#f08c00; }}
|
|
157
157
|
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: var(--bg); color: var(--text); line-height: 1.6; }
|
|
158
158
|
.layout { display: flex; min-height: 100vh; }
|
|
159
159
|
.sidebar { width: 240px; background: var(--surface); border-right: 1px solid var(--border); position: fixed; top: 0; left: 0; bottom: 0; display: flex; flex-direction: column; }
|
|
@@ -164,7 +164,7 @@ function badge(string $status): string {
|
|
|
164
164
|
.nav-sec { font-size:10px; text-transform:uppercase; letter-spacing:0.08em; color:var(--muted); padding:12px 20px 4px; }
|
|
165
165
|
.nav a { display:flex; align-items:center; gap:10px; padding:10px 20px; color:var(--dim); text-decoration:none; font-size:13px; }
|
|
166
166
|
.nav a:hover { color:var(--text); background:rgba(255,255,255,0.03); }
|
|
167
|
-
.nav a.active { color:var(--primary); background:rgba(
|
|
167
|
+
.nav a.active { color:var(--primary); background:rgba(232,67,147,0.12); border-right:2px solid var(--primary); }
|
|
168
168
|
.sidebar-footer { padding:16px 20px; border-top:1px solid var(--border); font-size:12px; }
|
|
169
169
|
.content { flex:1; margin-left:240px; padding:32px; max-width:1100px; }
|
|
170
170
|
h2.title { font-size:22px; font-weight:700; margin-bottom:4px; }
|
|
@@ -182,7 +182,7 @@ function badge(string $status): string {
|
|
|
182
182
|
.btn { display:inline-flex; align-items:center; padding:8px 16px; border-radius:var(--r); font-size:13px; font-weight:600; cursor:pointer; border:1px solid var(--border); background:var(--surface); color:var(--text); text-decoration:none; }
|
|
183
183
|
.btn:hover { background:rgba(255,255,255,0.05); }
|
|
184
184
|
.btn-p { background:var(--primary); border-color:var(--primary); color:#fff; }
|
|
185
|
-
.btn-p:hover { background:#
|
|
185
|
+
.btn-p:hover { background:#f06595; }
|
|
186
186
|
.btn-d { color:var(--danger); border-color:var(--danger); }
|
|
187
187
|
.btn-sm { padding:4px 10px; font-size:12px; }
|
|
188
188
|
.input { width:100%; padding:10px 14px; background:var(--bg); border:1px solid var(--border); border-radius:var(--r); color:var(--text); font-size:14px; }
|
|
@@ -387,7 +387,7 @@ function badge(string $status): string {
|
|
|
387
387
|
<input type="hidden" name="action" value="save_settings">
|
|
388
388
|
<div class="fg"><label class="fl">Organization Name</label><input class="input" name="name" value="<?= e($settings['name'] ?? '') ?>"></div>
|
|
389
389
|
<div class="fg"><label class="fl">Domain</label><input class="input" name="domain" value="<?= e($settings['domain'] ?? '') ?>" placeholder="agents.acme.com"></div>
|
|
390
|
-
<div class="fg"><label class="fl">Primary Color</label><input class="input" type="color" name="primaryColor" value="<?= e($settings['primaryColor'] ?? '#
|
|
390
|
+
<div class="fg"><label class="fl">Primary Color</label><input class="input" type="color" name="primaryColor" value="<?= e($settings['primaryColor'] ?? '#e84393') ?>" style="height:38px;padding:4px"></div>
|
|
391
391
|
<div></div>
|
|
392
392
|
<div><button class="btn btn-p" type="submit">Save Settings</button></div>
|
|
393
393
|
</form>
|
package/dashboards/python/app.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""
|
|
2
|
-
AgenticMail Enterprise Dashboard โ Python/Flask Edition
|
|
2
|
+
๐ AgenticMail Enterprise Dashboard โ Python/Flask Edition
|
|
3
3
|
|
|
4
4
|
Setup:
|
|
5
5
|
pip install flask requests
|
|
@@ -143,7 +143,7 @@ def settings():
|
|
|
143
143
|
result = api('/api/settings', 'PATCH', {
|
|
144
144
|
'name': request.form.get('name', ''),
|
|
145
145
|
'domain': request.form.get('domain', ''),
|
|
146
|
-
'primaryColor': request.form.get('primaryColor', '#
|
|
146
|
+
'primaryColor': request.form.get('primaryColor', '#e84393'),
|
|
147
147
|
})
|
|
148
148
|
flash('Settings saved!' if 'error' not in result else result['error'])
|
|
149
149
|
settings_data = api('/api/settings')
|
|
@@ -165,8 +165,8 @@ def render_page(page, **kwargs):
|
|
|
165
165
|
|
|
166
166
|
LOGIN_TEMPLATE = '''<!DOCTYPE html>
|
|
167
167
|
<html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
|
|
168
|
-
<title
|
|
169
|
-
<style>*{box-sizing:border-box;margin:0;padding:0}:root{--bg:#
|
|
168
|
+
<title>๐ AgenticMail Enterprise</title>
|
|
169
|
+
<style>*{box-sizing:border-box;margin:0;padding:0}:root,[data-theme=light]{--bg:#f8f9fa;--surface:#fff;--border:#dee2e6;--text:#212529;--dim:#495057;--muted:#868e96;--primary:#e84393;--success:#2b8a3e;--danger:#c92a2a;--warning:#e67700;--r:6px;color-scheme:light dark}[data-theme=dark]{--bg:#0f1114;--surface:#16181d;--border:#2c3038;--text:#e1e4e8;--dim:#b0b8c4;--muted:#6b7280;--primary:#f06595;--success:#37b24d;--danger:#f03e3e;--warning:#f08c00}@media(prefers-color-scheme:dark){:root:not([data-theme=light]){--bg:#0f1114;--surface:#16181d;--border:#2c3038;--text:#e1e4e8;--dim:#b0b8c4;--muted:#6b7280;--primary:#f06595;--success:#37b24d;--danger:#f03e3e;--warning:#f08c00}}body{font-family:-apple-system,sans-serif;background:var(--bg);color:var(--text);display:flex;align-items:center;justify-content:center;min-height:100vh}.box{width:380px;max-width:90vw}h1{text-align:center;font-size:22px;margin-bottom:4px}h1 em{font-style:normal;color:var(--primary)}.sub{text-align:center;color:var(--dim);font-size:13px;margin-bottom:32px}.err{background:rgba(239,68,68,0.1);border:1px solid var(--danger);border-radius:8px;padding:10px 14px;margin-bottom:16px;font-size:13px;color:var(--danger)}.fg{margin-bottom:14px}.fl{display:block;font-size:12px;color:var(--dim);margin-bottom:4px}.input{width:100%;padding:10px 14px;background:var(--surface);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px;outline:none}.input:focus{border-color:var(--primary)}.btn{width:100%;padding:10px;background:var(--primary);border:none;border-radius:8px;color:#fff;font-size:14px;font-weight:600;cursor:pointer}.btn:hover{background:#f06595}.info{text-align:center;margin-top:16px;font-size:11px;color:var(--muted)}</style></head>
|
|
170
170
|
<body><div class="box"><h1>๐ข <em>AgenticMail</em> Enterprise</h1><p class="sub">Sign in ยท Python Dashboard</p>
|
|
171
171
|
{% if error %}<div class="err">{{ error }}</div>{% endif %}
|
|
172
172
|
<form method="POST"><div class="fg"><label class="fl">Email</label><input class="input" type="email" name="email" required autofocus></div>
|
|
@@ -176,8 +176,8 @@ LOGIN_TEMPLATE = '''<!DOCTYPE html>
|
|
|
176
176
|
|
|
177
177
|
APP_TEMPLATE = '''<!DOCTYPE html>
|
|
178
178
|
<html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
|
|
179
|
-
<title
|
|
180
|
-
<style>*{box-sizing:border-box;margin:0;padding:0}:root{--bg:#
|
|
179
|
+
<title>๐ AgenticMail Enterprise โ Python</title>
|
|
180
|
+
<style>*{box-sizing:border-box;margin:0;padding:0}:root{--bg:#f8f9fa;--surface:#ffffff;--border:#dee2e6;--text:#212529;--dim:#868e96;--muted:#adb5bd;--primary:#e84393;--success:#22c55e;--danger:#ef4444;--warning:#f59e0b}body{font-family:-apple-system,sans-serif;background:var(--bg);color:var(--text)}.layout{display:flex;min-height:100vh}.sidebar{width:240px;background:var(--surface);border-right:1px solid var(--border);position:fixed;top:0;left:0;bottom:0;display:flex;flex-direction:column}.sidebar-h{padding:20px;border-bottom:1px solid var(--border)}.sidebar-h h2{font-size:16px}.sidebar-h h2 em{font-style:normal;color:var(--primary)}.sidebar-h small{font-size:11px;color:var(--muted);display:block;margin-top:2px}.nav{flex:1;padding:8px 0}.ns{font-size:10px;text-transform:uppercase;letter-spacing:0.08em;color:var(--muted);padding:12px 20px 4px}.nav a{display:flex;align-items:center;gap:10px;padding:10px 20px;color:var(--dim);text-decoration:none;font-size:13px}.nav a:hover{color:var(--text);background:rgba(255,255,255,0.03)}.nav a.active{color:var(--primary);background:rgba(232,67,147,0.12);border-right:2px solid var(--primary)}.sf{padding:16px 20px;border-top:1px solid var(--border);font-size:12px}.content{flex:1;margin-left:240px;padding:32px;max-width:1100px}h2.t{font-size:22px;font-weight:700;margin-bottom:4px}.desc{font-size:13px;color:var(--dim);margin-bottom:24px}.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:16px;margin-bottom:24px}.stat{background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:20px}.stat .l{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:0.06em}.stat .v{font-size:30px;font-weight:700;margin-top:4px}.card{background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:20px;margin-bottom:16px}.ct{font-size:13px;color:var(--dim);text-transform:uppercase;letter-spacing:0.05em;font-weight:600;margin-bottom:12px}table{width:100%;border-collapse:collapse;font-size:13px}th{text-align:left;padding:10px 12px;color:var(--muted);font-size:11px;text-transform:uppercase;letter-spacing:0.05em;border-bottom:1px solid var(--border)}td{padding:12px;border-bottom:1px solid var(--border)}tr:hover td{background:rgba(255,255,255,0.015)}.btn{display:inline-flex;align-items:center;padding:8px 16px;border-radius:8px;font-size:13px;font-weight:600;cursor:pointer;border:1px solid var(--border);background:var(--surface);color:var(--text);text-decoration:none}.btn:hover{background:rgba(255,255,255,0.05)}.btn-p{background:var(--primary);border-color:var(--primary);color:#fff}.btn-p:hover{background:#f06595}.btn-d{color:var(--danger);border-color:var(--danger)}.btn-sm{padding:4px 10px;font-size:12px}.input{width:100%;padding:10px 14px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px;outline:none}.input:focus{border-color:var(--primary)}.fg{margin-bottom:14px}.fl{display:block;font-size:12px;color:var(--dim);margin-bottom:4px;font-weight:500}.badge{display:inline-block;padding:2px 10px;border-radius:999px;font-size:11px;font-weight:600}.b-active{background:rgba(34,197,94,0.12);color:var(--success)}.b-archived{background:rgba(136,136,160,0.1);color:var(--dim)}.b-owner{background:rgba(245,158,11,0.12);color:var(--warning)}.b-admin{background:rgba(232,67,147,0.12);color:var(--primary)}.b-member{background:rgba(136,136,160,0.08);color:var(--dim)}.empty{text-align:center;padding:48px 20px;color:var(--muted)}.empty-i{font-size:36px;margin-bottom:10px}.flash{padding:12px 16px;border-radius:8px;margin-bottom:16px;font-size:13px;background:rgba(34,197,94,0.1);border:1px solid var(--success);color:var(--success)}</style></head>
|
|
181
181
|
<body><div class="layout">
|
|
182
182
|
<div class="sidebar"><div class="sidebar-h"><h2>๐ข <em>Agentic</em>Mail</h2><small>Enterprise ยท Python</small></div>
|
|
183
183
|
<div class="nav"><div class="ns">Overview</div>
|
|
@@ -255,7 +255,7 @@ APP_TEMPLATE = '''<!DOCTYPE html>
|
|
|
255
255
|
<form method="POST" style="display:grid;grid-template-columns:1fr 1fr;gap:14px">
|
|
256
256
|
<div class="fg"><label class="fl">Organization Name</label><input class="input" name="name" value="{{ settings.name|default('') }}"></div>
|
|
257
257
|
<div class="fg"><label class="fl">Domain</label><input class="input" name="domain" value="{{ settings.domain|default('') }}" placeholder="agents.acme.com"></div>
|
|
258
|
-
<div class="fg"><label class="fl">Primary Color</label><input class="input" type="color" name="primaryColor" value="{{ settings.primaryColor|default('#
|
|
258
|
+
<div class="fg"><label class="fl">Primary Color</label><input class="input" type="color" name="primaryColor" value="{{ settings.primaryColor|default('#e84393') }}" style="height:38px;padding:4px"></div>
|
|
259
259
|
<div></div><div><button class="btn btn-p" type="submit">Save Settings</button></div></form></div>
|
|
260
260
|
<div class="card"><div class="ct">Plan</div><span class="badge b-active" style="font-size:14px;padding:4px 12px">{{ (settings.plan or 'free')|upper }}</span>
|
|
261
261
|
<span style="font-size:13px;color:var(--dim);margin-left:12px">Subdomain: {{ settings.subdomain|default('not set') }}.agenticmail.cloud</span></div>
|
|
@@ -267,7 +267,7 @@ Status: <span style="color:{{ 'var(--success)' if retention.enabled else 'var(--
|
|
|
267
267
|
</div></div></body></html>'''
|
|
268
268
|
|
|
269
269
|
if __name__ == '__main__':
|
|
270
|
-
print(f'\n๐ข AgenticMail Enterprise Dashboard (Python/Flask)')
|
|
270
|
+
print(f'\n๐ข ๐ AgenticMail Enterprise Dashboard (Python/Flask)')
|
|
271
271
|
print(f' API: {API_URL}')
|
|
272
272
|
print(f' Dashboard: http://localhost:5000\n')
|
|
273
273
|
app.run(debug=True, port=5000)
|
package/dashboards/ruby/app.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# AgenticMail Enterprise Dashboard โ Ruby/Sinatra Edition
|
|
1
|
+
# ๐ AgenticMail Enterprise Dashboard โ Ruby/Sinatra Edition
|
|
2
2
|
#
|
|
3
3
|
# Setup:
|
|
4
4
|
# gem install sinatra json
|
|
@@ -46,7 +46,7 @@ end
|
|
|
46
46
|
|
|
47
47
|
def badge(status)
|
|
48
48
|
colors = { 'active' => '#22c55e', 'archived' => '#888', 'suspended' => '#ef4444',
|
|
49
|
-
'owner' => '#f59e0b', 'admin' => '#
|
|
49
|
+
'owner' => '#f59e0b', 'admin' => '#e84393', 'member' => '#888', 'viewer' => '#555' }
|
|
50
50
|
c = colors[status.to_s] || '#888'
|
|
51
51
|
"<span style='display:inline-block;padding:2px 10px;border-radius:999px;font-size:11px;font-weight:600;background:#{c}20;color:#{c}'>#{status}</span>"
|
|
52
52
|
end
|
|
@@ -59,8 +59,8 @@ def layout(page, &block)
|
|
|
59
59
|
erb_str = <<~HTML
|
|
60
60
|
<!DOCTYPE html>
|
|
61
61
|
<html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
|
|
62
|
-
<title
|
|
63
|
-
<style>*{box-sizing:border-box;margin:0;padding:0}:root{--bg:#
|
|
62
|
+
<title>๐ AgenticMail Enterprise โ Ruby</title>
|
|
63
|
+
<style>*{box-sizing:border-box;margin:0;padding:0}:root,[data-theme=light]{--bg:#f8f9fa;--surface:#fff;--border:#dee2e6;--text:#212529;--dim:#495057;--muted:#868e96;--primary:#e84393;--success:#2b8a3e;--danger:#c92a2a;--warning:#e67700;--r:6px;color-scheme:light dark}[data-theme=dark]{--bg:#0f1114;--surface:#16181d;--border:#2c3038;--text:#e1e4e8;--dim:#b0b8c4;--muted:#6b7280;--primary:#f06595;--success:#37b24d;--danger:#f03e3e;--warning:#f08c00}@media(prefers-color-scheme:dark){:root:not([data-theme=light]){--bg:#0f1114;--surface:#16181d;--border:#2c3038;--text:#e1e4e8;--dim:#b0b8c4;--muted:#6b7280;--primary:#f06595;--success:#37b24d;--danger:#f03e3e;--warning:#f08c00}}body{font-family:-apple-system,sans-serif;background:var(--bg);color:var(--text)}.layout{display:flex;min-height:100vh}.sidebar{width:240px;background:var(--surface);border-right:1px solid var(--border);position:fixed;top:0;left:0;bottom:0;display:flex;flex-direction:column}.sh{padding:20px;border-bottom:1px solid var(--border)}.sh h2{font-size:16px}.sh h2 em{font-style:normal;color:var(--primary)}.sh small{font-size:11px;color:var(--muted);display:block;margin-top:2px}.nav{flex:1;padding:8px 0}.ns{font-size:10px;text-transform:uppercase;letter-spacing:0.08em;color:var(--muted);padding:12px 20px 4px}.nav a{display:flex;align-items:center;gap:10px;padding:10px 20px;color:var(--dim);text-decoration:none;font-size:13px}.nav a:hover{color:var(--text);background:rgba(255,255,255,0.03)}.nav a.on{color:var(--primary);background:rgba(232,67,147,0.12);border-right:2px solid var(--primary)}.sf{padding:16px 20px;border-top:1px solid var(--border);font-size:12px}.content{flex:1;margin-left:240px;padding:32px;max-width:1100px}h2.t{font-size:22px;font-weight:700;margin-bottom:4px}.desc{font-size:13px;color:var(--dim);margin-bottom:24px}.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:16px;margin-bottom:24px}.stat{background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:20px}.stat .l{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:0.06em}.stat .v{font-size:30px;font-weight:700;margin-top:4px}.card{background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:20px;margin-bottom:16px}.ct{font-size:13px;color:var(--dim);text-transform:uppercase;letter-spacing:0.05em;font-weight:600;margin-bottom:12px}table{width:100%;border-collapse:collapse;font-size:13px}th{text-align:left;padding:10px 12px;color:var(--muted);font-size:11px;text-transform:uppercase;letter-spacing:0.05em;border-bottom:1px solid var(--border)}td{padding:12px;border-bottom:1px solid var(--border)}tr:hover td{background:rgba(255,255,255,0.015)}.btn{display:inline-flex;align-items:center;padding:8px 16px;border-radius:8px;font-size:13px;font-weight:600;cursor:pointer;border:1px solid var(--border);background:var(--surface);color:var(--text);text-decoration:none}.btn:hover{background:rgba(255,255,255,0.05)}.btn-p{background:var(--primary);border-color:var(--primary);color:#fff}.btn-d{color:var(--danger);border-color:var(--danger)}.btn-sm{padding:4px 10px;font-size:12px}.input{width:100%;padding:10px 14px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px}.fg{margin-bottom:14px}.fl{display:block;font-size:12px;color:var(--dim);margin-bottom:4px}.empty{text-align:center;padding:48px 20px;color:var(--muted)}.flash{padding:12px 16px;border-radius:8px;margin-bottom:16px;font-size:13px;background:rgba(34,197,94,0.1);border:1px solid var(--success);color:var(--success)}</style></head>
|
|
64
64
|
<body><div class="layout">
|
|
65
65
|
<div class="sidebar"><div class="sh"><h2>๐ข <em>Agentic</em>Mail</h2><small>Enterprise ยท Ruby</small></div>
|
|
66
66
|
<div class="nav"><div class="ns">Overview</div><a href="/" class="#{page == 'dashboard' ? 'on' : ''}">๐ Dashboard</a>
|
|
@@ -83,8 +83,8 @@ end
|
|
|
83
83
|
|
|
84
84
|
get '/login' do
|
|
85
85
|
<<~HTML
|
|
86
|
-
<!DOCTYPE html><html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0"><title
|
|
87
|
-
<style>*{box-sizing:border-box;margin:0;padding:0}body{font-family:-apple-system,sans-serif;background:#
|
|
86
|
+
<!DOCTYPE html><html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0"><title>๐ AgenticMail Enterprise</title>
|
|
87
|
+
<style>*{box-sizing:border-box;margin:0;padding:0}body{font-family:-apple-system,sans-serif;background:#f8f9fa;color:#212529;display:flex;align-items:center;justify-content:center;min-height:100vh}.box{width:380px}h1{text-align:center;font-size:22px;margin-bottom:4px}h1 em{font-style:normal;color:#e84393}.sub{text-align:center;color:#868e96;font-size:13px;margin-bottom:32px}.fg{margin-bottom:14px}.fl{display:block;font-size:12px;color:#868e96;margin-bottom:4px}.input{width:100%;padding:10px 14px;background:#ffffff;border:1px solid #dee2e6;border-radius:8px;color:#212529;font-size:14px;outline:none}.input:focus{border-color:#e84393}.btn{width:100%;padding:10px;background:#e84393;border:none;border-radius:8px;color:#fff;font-size:14px;font-weight:600;cursor:pointer}</style></head>
|
|
88
88
|
<body><div class="box"><h1>๐ข <em>AgenticMail</em> Enterprise</h1><p class="sub">Sign in ยท Ruby Dashboard</p>
|
|
89
89
|
<form method="POST" action="/login"><div class="fg"><label class="fl">Email</label><input class="input" type="email" name="email" required></div>
|
|
90
90
|
<div class="fg"><label class="fl">Password</label><input class="input" type="password" name="password" required></div>
|
|
@@ -190,6 +190,6 @@ get '/settings' do
|
|
|
190
190
|
}
|
|
191
191
|
end
|
|
192
192
|
|
|
193
|
-
puts "\n๐ข AgenticMail Enterprise Dashboard (Ruby/Sinatra)"
|
|
193
|
+
puts "\n๐ข ๐ AgenticMail Enterprise Dashboard (Ruby/Sinatra)"
|
|
194
194
|
puts " API: #{API_URL}"
|
|
195
195
|
puts " Dashboard: http://localhost:4567\n"
|