style(headers): update all page header titles and add HelpTrigger buttons matching demoplace.my.id
This commit is contained in:
1 parent
fb75711994
commit
36fe496566
20 files changed
+532
-60
No files matched your search
@@ -0,0 +1,66 @@
|
||||
const { Client } = require('ssh2');
|
||||
|
||||
const remoteScript = `
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const root = '/home/adminbackend/web/demoplace.my.id/public_html/.next/standalone/.next/server/app/(dashboard)';
|
||||
|
||||
function scanDir(dir) {
|
||||
const results = [];
|
||||
if (!fs.existsSync(dir)) return results;
|
||||
const items = fs.readdirSync(dir, { withFileTypes: true });
|
||||
for (const item of items) {
|
||||
const fullPath = path.join(dir, item.name);
|
||||
if (item.isDirectory()) {
|
||||
results.push(...scanDir(fullPath));
|
||||
} else if (item.name.endsWith('.html') || item.name.endsWith('.js')) {
|
||||
results.push(fullPath);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
console.log('=== AUDITING ALL PAGE HEADERS AND TITLES ON DEMOPLACE.MY.ID ===\\n');
|
||||
|
||||
const files = scanDir(root);
|
||||
files.forEach(file => {
|
||||
const content = fs.readFileSync(file, 'utf8');
|
||||
const rel = path.relative(root, file);
|
||||
|
||||
// Extract <h2> or <h1> or header titles
|
||||
const h2s = [];
|
||||
const h2Match = content.matchAll(/<h2[^>]*>(.*?)<\/h2>/gi);
|
||||
for (const m of h2Match) {
|
||||
const clean = m[1].replace(/<[^>]+>/g, '').trim();
|
||||
if (clean && !h2s.includes(clean)) h2s.push(clean);
|
||||
}
|
||||
|
||||
// Extract Learn This Page triggers
|
||||
const hasHelpTrigger = content.includes('Learn This Page');
|
||||
|
||||
if (h2s.length > 0 || hasHelpTrigger) {
|
||||
console.log('Page Route File:', rel);
|
||||
if (h2s.length > 0) console.log(' Headers (H2):', h2s.join(' | '));
|
||||
console.log(' Has Learn This Page Button:', hasHelpTrigger);
|
||||
console.log('---');
|
||||
}
|
||||
});
|
||||
`;
|
||||
|
||||
const conn = new Client();
|
||||
conn.on('ready', () => {
|
||||
conn.exec(`node -e ${JSON.stringify(remoteScript)}`, (err, stream) => {
|
||||
let out = '';
|
||||
stream.on('data', d => out += d);
|
||||
stream.on('close', () => {
|
||||
console.log(out);
|
||||
conn.end();
|
||||
});
|
||||
});
|
||||
}).connect({
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH'
|
||||
});
|
||||
@@ -0,0 +1,62 @@
|
||||
const SftpClient = require('ssh2-sftp-client');
|
||||
const { Client } = require('ssh2');
|
||||
|
||||
const remoteExtractScript = `
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const root = '/home/adminbackend/web/demoplace.my.id/public_html/.next/standalone/.next/server/chunks';
|
||||
|
||||
console.log('=== EXTRACTING ALL PAGE HEADERS FROM CHUNKS ===\\n');
|
||||
|
||||
const files = fs.readdirSync(root);
|
||||
files.forEach(f => {
|
||||
if (!f.endsWith('.js')) return;
|
||||
const content = fs.readFileSync(path.join(root, f), 'utf8');
|
||||
|
||||
// Match header titles in React JSX: e.g. text-3xl font-bold ... >TitleText<
|
||||
const titleMatches = content.matchAll(/text-3xl[^>]*>([^<]{3,40})</gi);
|
||||
for (const m of titleMatches) {
|
||||
console.log(\`Chunk \${f}: "\${m[1].trim()}"\`);
|
||||
}
|
||||
|
||||
// Match tab names in React JSX
|
||||
const tabMatches = content.matchAll(/role="tab"[^>]*>([^<]{3,30})</gi);
|
||||
for (const m of tabMatches) {
|
||||
console.log(\`Chunk \${f} Tab: "\${m[1].trim()}"\`);
|
||||
}
|
||||
});
|
||||
`;
|
||||
|
||||
async function main() {
|
||||
const sftp = new SftpClient();
|
||||
await sftp.connect({
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH'
|
||||
});
|
||||
|
||||
const remoteScriptPath = '/home/adminbackend/extract_client_titles.js';
|
||||
await sftp.put(Buffer.from(remoteExtractScript), remoteScriptPath);
|
||||
await sftp.end();
|
||||
|
||||
const conn = new Client();
|
||||
conn.on('ready', () => {
|
||||
conn.exec(`node ${remoteScriptPath}`, (err, stream) => {
|
||||
let out = '';
|
||||
stream.on('data', d => out += d);
|
||||
stream.on('close', () => {
|
||||
console.log(out);
|
||||
conn.end();
|
||||
});
|
||||
});
|
||||
}).connect({
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH'
|
||||
});
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -0,0 +1,69 @@
|
||||
const SftpClient = require('ssh2-sftp-client');
|
||||
const { Client } = require('ssh2');
|
||||
|
||||
const remoteExtractScript = `
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const root = '/home/adminbackend/web/demoplace.my.id/public_html/.next/standalone/.next/server';
|
||||
|
||||
console.log('=== EXTRACTING ALL PAGE HEADERS FROM STANDALONE BUILD ===\\n');
|
||||
|
||||
function scan(dir) {
|
||||
if (!fs.existsSync(dir)) return;
|
||||
const items = fs.readdirSync(dir, { withFileTypes: true });
|
||||
for (const item of items) {
|
||||
const full = path.join(dir, item.name);
|
||||
if (item.isDirectory()) {
|
||||
scan(full);
|
||||
} else if (item.name.endsWith('.js') || item.name.endsWith('.html')) {
|
||||
const content = fs.readFileSync(full, 'utf8');
|
||||
|
||||
// Look for H2/H1 page header titles or page metadata
|
||||
const matches = content.matchAll(/<h[12][^>]*>([\\s\\S]*?)<\\/h[12]>/gi);
|
||||
for (const m of matches) {
|
||||
const clean = m[1].replace(/<[^>]+>/g, '').trim();
|
||||
if (clean && clean.length > 2 && clean.length < 60 && !clean.includes('{') && !clean.includes('function')) {
|
||||
console.log(\`File: \${path.relative(root, full)}\`);
|
||||
console.log(\` Header: "\${clean}"\`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scan(path.join(root, 'app/(dashboard)'));
|
||||
`;
|
||||
|
||||
async function main() {
|
||||
const sftp = new SftpClient();
|
||||
await sftp.connect({
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH'
|
||||
});
|
||||
|
||||
const remoteScriptPath = '/home/adminbackend/extract_standalone.js';
|
||||
await sftp.put(Buffer.from(remoteExtractScript), remoteScriptPath);
|
||||
await sftp.end();
|
||||
|
||||
const conn = new Client();
|
||||
conn.on('ready', () => {
|
||||
conn.exec(`node ${remoteScriptPath}`, (err, stream) => {
|
||||
let out = '';
|
||||
stream.on('data', d => out += d);
|
||||
stream.on('close', () => {
|
||||
console.log(out);
|
||||
conn.end();
|
||||
});
|
||||
});
|
||||
}).connect({
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH'
|
||||
});
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -0,0 +1,44 @@
|
||||
const { Client } = require('ssh2');
|
||||
|
||||
const conn = new Client();
|
||||
conn.on('ready', () => {
|
||||
// Execute a shell script on remote server
|
||||
conn.exec(`python3 -c "
|
||||
import os, re
|
||||
|
||||
root = '/home/adminbackend/web/demoplace.my.id/public_html/.next/standalone/.next/server/app/(dashboard)'
|
||||
|
||||
for dirpath, dirnames, filenames in os.walk(root):
|
||||
for f in filenames:
|
||||
if f.endswith('.html') or f.endswith('.js'):
|
||||
full = os.path.join(dirpath, f)
|
||||
rel = os.path.relpath(full, root)
|
||||
try:
|
||||
content = open(full, 'r', encoding='utf-8', errors='ignore').read()
|
||||
|
||||
h2s = re.findall(r'<h[12][^>]*>(.*?)</h[12]>', content)
|
||||
clean_h2s = [re.sub(r'<[^>]+>', '', h).strip() for h in h2s if h.strip()]
|
||||
|
||||
has_learn = 'Learn This Page' in content
|
||||
|
||||
if clean_h2s or has_learn:
|
||||
print(f'Route File: {rel}')
|
||||
print(f' Headers: {\" | \".join(clean_h2s)}')
|
||||
print(f' Learn This Page Button: {has_learn}')
|
||||
print('-' * 40)
|
||||
except Exception as e:
|
||||
pass
|
||||
"`, (err, stream) => {
|
||||
let out = '';
|
||||
stream.on('data', d => out += d);
|
||||
stream.on('close', () => {
|
||||
console.log(out);
|
||||
conn.end();
|
||||
});
|
||||
});
|
||||
}).connect({
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH'
|
||||
});
|
||||
@@ -0,0 +1,80 @@
|
||||
const SftpClient = require('ssh2-sftp-client');
|
||||
const { Client } = require('ssh2');
|
||||
|
||||
const remoteScanScript = `
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const root = '/home/adminbackend/web/demoplace.my.id/public_html/.next';
|
||||
|
||||
const targetTitles = [
|
||||
'Overview Dashboard',
|
||||
'Summary Overview',
|
||||
'DPI MetaData',
|
||||
'BackOne Metadata',
|
||||
'Network Topology',
|
||||
'Network Infrastructure',
|
||||
'Traffic Categories',
|
||||
'Threat Intelligence',
|
||||
'Detected Threats',
|
||||
'App Lookup',
|
||||
'Application Database',
|
||||
'Encryption Audit',
|
||||
'Security & Encryption Audit'
|
||||
];
|
||||
|
||||
console.log('=== MATCHING TARGET TITLES IN REMOTE NEXT BUILD ===\\n');
|
||||
|
||||
function scan(dir) {
|
||||
if (!fs.existsSync(dir)) return;
|
||||
const items = fs.readdirSync(dir, { withFileTypes: true });
|
||||
for (const item of items) {
|
||||
const full = path.join(dir, item.name);
|
||||
if (item.isDirectory()) {
|
||||
scan(full);
|
||||
} else if (item.name.endsWith('.js') || item.name.endsWith('.html')) {
|
||||
const content = fs.readFileSync(full, 'utf8');
|
||||
targetTitles.forEach(t => {
|
||||
if (content.includes(t)) {
|
||||
console.log(\`Found "\${t}" in file: \${path.relative(root, full)}\`);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scan(root);
|
||||
`;
|
||||
|
||||
async function main() {
|
||||
const sftp = new SftpClient();
|
||||
await sftp.connect({
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH'
|
||||
});
|
||||
|
||||
const remoteScriptPath = '/home/adminbackend/scan_strings.js';
|
||||
await sftp.put(Buffer.from(remoteScanScript), remoteScriptPath);
|
||||
await sftp.end();
|
||||
|
||||
const conn = new Client();
|
||||
conn.on('ready', () => {
|
||||
conn.exec(`node ${remoteScriptPath}`, (err, stream) => {
|
||||
let out = '';
|
||||
stream.on('data', d => out += d);
|
||||
stream.on('close', () => {
|
||||
console.log(out);
|
||||
conn.end();
|
||||
});
|
||||
});
|
||||
}).connect({
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH'
|
||||
});
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -0,0 +1,94 @@
|
||||
const SftpClient = require('ssh2-sftp-client');
|
||||
const { Client } = require('ssh2');
|
||||
|
||||
const remoteAuditScript = `
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const root = '/home/adminbackend/web/demoplace.my.id/public_html';
|
||||
|
||||
console.log('====================================================');
|
||||
console.log(' FULL COMPONENT & PAGE AUDIT OF DEMOPLACE.MY.ID ');
|
||||
console.log('====================================================');
|
||||
|
||||
// 1. Audit Client/Server Chunks for Page Headers & HelpTriggers
|
||||
const chunksDir = path.join(root, '.next/standalone/.next/server/chunks');
|
||||
if (fs.existsSync(chunksDir)) {
|
||||
const files = fs.readdirSync(chunksDir);
|
||||
files.forEach(f => {
|
||||
if (!f.endsWith('.js')) return;
|
||||
const content = fs.readFileSync(path.join(chunksDir, f), 'utf8');
|
||||
|
||||
// Look for page headers or title definitions
|
||||
const headerMatch = content.match(/["']([A-Z][A-Za-z0-9\\s]{3,35})["'],\\s*description:/);
|
||||
if (headerMatch) {
|
||||
console.log(\`[Chunk \${f}] Found Header Definition: "\${headerMatch[1]}"\`);
|
||||
}
|
||||
|
||||
if (content.includes('Learn This Page')) {
|
||||
console.log(\`[Chunk \${f}] Contains "Learn This Page" button\`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 2. Audit Page Source files in src/app/(dashboard)
|
||||
const appSrcDir = path.join(root, 'src/app/(dashboard)');
|
||||
if (fs.existsSync(appSrcDir)) {
|
||||
function scan(dir) {
|
||||
const items = fs.readdirSync(dir, { withFileTypes: true });
|
||||
for (const item of items) {
|
||||
const full = path.join(dir, item.name);
|
||||
if (item.isDirectory()) {
|
||||
scan(full);
|
||||
} else if (item.name === 'page.tsx' || item.name.endsWith('.tsx')) {
|
||||
const content = fs.readFileSync(full, 'utf8');
|
||||
const rel = path.relative(appSrcDir, full);
|
||||
|
||||
// Find H2 or H1
|
||||
const h2 = content.match(/<h[12][^>]*>([\\s\\S]*?)<\\/h[12]>/i);
|
||||
const titleText = h2 ? h2[1].replace(/<[^>]+>/g, '').trim().split('\\n')[0] : 'None';
|
||||
const hasHelp = content.includes('HelpTrigger') || content.includes('Learn This Page');
|
||||
|
||||
console.log(\`Page File: \${rel}\`);
|
||||
console.log(\` Header Title : \${titleText}\`);
|
||||
console.log(\` Has HelpButton: \${hasHelp}\`);
|
||||
console.log('----------------------------------------------------');
|
||||
}
|
||||
}
|
||||
}
|
||||
scan(appSrcDir);
|
||||
}
|
||||
`;
|
||||
|
||||
async function main() {
|
||||
const sftp = new SftpClient();
|
||||
await sftp.connect({
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH'
|
||||
});
|
||||
|
||||
const remoteScriptPath = '/home/adminbackend/audit_remote.js';
|
||||
await sftp.put(Buffer.from(remoteAuditScript), remoteScriptPath);
|
||||
await sftp.end();
|
||||
|
||||
const conn = new Client();
|
||||
conn.on('ready', () => {
|
||||
conn.exec(`node ${remoteScriptPath}`, (err, stream) => {
|
||||
let out = '';
|
||||
stream.on('data', d => out += d);
|
||||
stream.on('close', () => {
|
||||
console.log(out);
|
||||
conn.end();
|
||||
});
|
||||
});
|
||||
}).connect({
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH'
|
||||
});
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -14,6 +14,7 @@ import { usePollingKey } from "@/lib/usePolling";
|
||||
import { AgentModals } from "@/components/admin/AgentModals";
|
||||
import ExternalAccountModal from "@/components/admin/ExternalAccountModal";
|
||||
import { getAgentColumns, getExternalAccountColumns } from "./columns";
|
||||
import { HelpTrigger } from "@/components/help/HelpTrigger";
|
||||
|
||||
export default function AgentsPage() {
|
||||
const router = useRouter();
|
||||
@@ -175,20 +176,25 @@ export default function AgentsPage() {
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-2xl font-bold tracking-tight text-white flex items-center gap-3">
|
||||
<Server className="w-6 h-6 text-primary" />
|
||||
Agents Inventory
|
||||
{isLoading && <Loader2 className="w-5 h-5 animate-spin text-muted-foreground" />}
|
||||
</h2>
|
||||
{(role === 'SUPER_ADMIN' || role === 'TENANT_ADMIN') && (
|
||||
<button
|
||||
onClick={() => setIsCreateOpen(true)}
|
||||
className="flex items-center gap-2 bg-primary hover:bg-primary/95 text-primary-foreground px-4 py-2 rounded-xl text-sm font-semibold transition-all shadow-lg shadow-blue-500/10"
|
||||
>
|
||||
<Plus className="w-4 h-4" />
|
||||
Provision Agent
|
||||
</button>
|
||||
)}
|
||||
<div>
|
||||
<h2 className="text-3xl font-bold tracking-tight text-white flex items-center gap-3">
|
||||
Agents Inventory
|
||||
{isLoading && <Loader2 className="w-5 h-5 animate-spin text-muted-foreground" />}
|
||||
</h2>
|
||||
<p className="text-muted-foreground mt-1">Managed DPI probes, remote collectors, and probe infrastructure.</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
{(role === 'SUPER_ADMIN' || role === 'TENANT_ADMIN') && (
|
||||
<button
|
||||
onClick={() => setIsCreateOpen(true)}
|
||||
className="flex items-center gap-2 bg-primary hover:bg-primary/95 text-primary-foreground px-4 py-2 rounded-xl text-sm font-semibold transition-all shadow-lg shadow-blue-500/10"
|
||||
>
|
||||
<Plus className="w-4 h-4" />
|
||||
Provision Agent
|
||||
</button>
|
||||
)}
|
||||
<HelpTrigger pageId="agents" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{error && (
|
||||
|
||||
@@ -11,6 +11,7 @@ import { Loader2, ChevronRight, Globe } from "lucide-react";
|
||||
import { UniversalFilters, useUniversalFilterState, FilterConfig } from "@/components/ui/UniversalFilters";
|
||||
import { fmtBytes, getAppFavicon, formatAppLabel } from "@/lib/utils";
|
||||
import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip as RechartsTooltip, ResponsiveContainer } from "recharts";
|
||||
import { HelpTrigger } from "@/components/help/HelpTrigger";
|
||||
|
||||
export default function AppsPage() {
|
||||
const [mounted, setMounted] = useState(false);
|
||||
@@ -130,7 +131,7 @@ export default function AppsPage() {
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h2 className="text-2xl font-bold tracking-tight text-white flex items-center gap-3">
|
||||
<h2 className="text-3xl font-bold tracking-tight text-white flex items-center gap-3">
|
||||
Applications
|
||||
{isLoading && <Loader2 className="w-5 h-5 animate-spin text-muted-foreground" />}
|
||||
</h2>
|
||||
@@ -138,6 +139,7 @@ export default function AppsPage() {
|
||||
Click any application to see which agents and devices are using it.
|
||||
</p>
|
||||
</div>
|
||||
<HelpTrigger pageId="apps" />
|
||||
</div>
|
||||
|
||||
<UniversalFilters
|
||||
|
||||
@@ -11,6 +11,7 @@ import { fmtBytes } from "@/lib/utils";
|
||||
import { Loader2, ChevronRight, ChevronDown } from "lucide-react";
|
||||
|
||||
import { UniversalFilters, useUniversalFilterState, FilterConfig } from "@/components/ui/UniversalFilters";
|
||||
import { HelpTrigger } from "@/components/help/HelpTrigger";
|
||||
|
||||
export default function DevicesPage() {
|
||||
const [mounted, setMounted] = useState(false);
|
||||
@@ -171,6 +172,7 @@ export default function DevicesPage() {
|
||||
<span className="text-slate-500 text-xs">Click an IP to see app usage & flows.</span>
|
||||
</p>
|
||||
</div>
|
||||
<HelpTrigger pageId="devices" />
|
||||
</div>
|
||||
|
||||
<UniversalFilters
|
||||
|
||||
@@ -7,6 +7,7 @@ import { DataTable, Column } from "@/components/ui/DataTable";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/Card";
|
||||
import { Loader2 } from "lucide-react";
|
||||
import { UniversalFilters, useUniversalFilterState, FilterConfig } from "@/components/ui/UniversalFilters";
|
||||
import { HelpTrigger } from "@/components/help/HelpTrigger";
|
||||
|
||||
export default function DNSPage() {
|
||||
const [mounted, setMounted] = useState(false);
|
||||
@@ -95,11 +96,15 @@ export default function DNSPage() {
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-2xl font-bold tracking-tight text-white flex items-center gap-3">
|
||||
DNS Intelligence
|
||||
{isLoading && <Loader2 className="w-5 h-5 animate-spin text-muted-foreground" />}
|
||||
</h2>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h2 className="text-3xl font-bold tracking-tight text-white flex items-center gap-3">
|
||||
DNS Intelligence
|
||||
{isLoading && <Loader2 className="w-5 h-5 animate-spin text-muted-foreground" />}
|
||||
</h2>
|
||||
<p className="text-muted-foreground mt-1">Domain Name System resolution analytics and query logs.</p>
|
||||
</div>
|
||||
<HelpTrigger pageId="dns" />
|
||||
</div>
|
||||
|
||||
<UniversalFilters
|
||||
|
||||
@@ -24,6 +24,8 @@ function ClickHint() {
|
||||
);
|
||||
}
|
||||
|
||||
import { HelpTrigger } from "@/components/help/HelpTrigger";
|
||||
|
||||
export default function DpiAnalyticsPage() {
|
||||
const { timeRange } = useTimeFilter();
|
||||
// Detail panel state
|
||||
@@ -59,12 +61,15 @@ export default function DpiAnalyticsPage() {
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold text-white tracking-tight">BackOne Metadata</h1>
|
||||
<p className="text-slate-400 mt-2">
|
||||
Deep Packet Inspection metadata and fingerprinting.{" "}
|
||||
<span className="text-blue-400 text-sm">Click any row to view device-level detail.</span>
|
||||
</p>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold text-white tracking-tight">DPI MetaData</h1>
|
||||
<p className="text-slate-400 mt-2">
|
||||
Deep Packet Inspection metadata and fingerprinting.{" "}
|
||||
<span className="text-blue-400 text-sm">Click any row to view device-level detail.</span>
|
||||
</p>
|
||||
</div>
|
||||
<HelpTrigger pageId="dpi-analytics" />
|
||||
</div>
|
||||
|
||||
<Tabs>
|
||||
|
||||
@@ -11,6 +11,7 @@ import { UniversalFilters, useUniversalFilterState, FilterConfig } from "@/compo
|
||||
|
||||
import { useSearchParams } from "next/navigation";
|
||||
import { Suspense } from "react";
|
||||
import { HelpTrigger } from "@/components/help/HelpTrigger";
|
||||
|
||||
|
||||
|
||||
@@ -158,10 +159,14 @@ function EventsContent() {
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-2xl font-bold tracking-tight text-white flex items-center gap-3">
|
||||
Network Events
|
||||
{isLoading && <Loader2 className="w-5 h-5 animate-spin text-muted-foreground" />}
|
||||
</h2>
|
||||
<div>
|
||||
<h2 className="text-3xl font-bold tracking-tight text-white flex items-center gap-3">
|
||||
Network Events
|
||||
{isLoading && <Loader2 className="w-5 h-5 animate-spin text-muted-foreground" />}
|
||||
</h2>
|
||||
<p className="text-muted-foreground mt-1">Real-time system, security, and interface network log events.</p>
|
||||
</div>
|
||||
<HelpTrigger pageId="events" />
|
||||
</div>
|
||||
|
||||
<UniversalFilters
|
||||
|
||||
@@ -10,6 +10,7 @@ import { fmtBytes, formatAppLabel } from "@/lib/utils";
|
||||
import { IpDetails } from "@/components/ui/IpDetails";
|
||||
import { DeviceDetailModal } from "@/components/ui/DeviceDetailModal";
|
||||
import { UniversalFilters, useUniversalFilterState, FilterConfig } from "@/components/ui/UniversalFilters";
|
||||
import { HelpTrigger } from "@/components/help/HelpTrigger";
|
||||
|
||||
function explainAppOrPort(appLabel: string | null, domain: string | null, port: number) {
|
||||
const label = appLabel || domain || "";
|
||||
@@ -208,10 +209,14 @@ export default function FlowsPage() {
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-2xl font-bold tracking-tight text-white flex items-center gap-3">
|
||||
Active Flows
|
||||
{isLoading && <Loader2 className="w-5 h-5 animate-spin text-muted-foreground" />}
|
||||
</h2>
|
||||
<div>
|
||||
<h2 className="text-3xl font-bold tracking-tight text-white flex items-center gap-3">
|
||||
Active Flows
|
||||
{isLoading && <Loader2 className="w-5 h-5 animate-spin text-muted-foreground" />}
|
||||
</h2>
|
||||
<p className="text-muted-foreground mt-1">Real-time IP connection flows and protocol analysis.</p>
|
||||
</div>
|
||||
<HelpTrigger pageId="flows" />
|
||||
</div>
|
||||
|
||||
<UniversalFilters
|
||||
|
||||
@@ -8,6 +8,7 @@ import { Loader2 } from "lucide-react";
|
||||
import { fmtBytes } from "@/lib/utils";
|
||||
import { WorldMap } from "@/components/ui/WorldMap";
|
||||
import { UniversalFilters, useUniversalFilterState, FilterConfig } from "@/components/ui/UniversalFilters";
|
||||
import { HelpTrigger } from "@/components/help/HelpTrigger";
|
||||
|
||||
export default function GeographyPage() {
|
||||
const [mounted, setMounted] = useState(false);
|
||||
@@ -102,14 +103,15 @@ export default function GeographyPage() {
|
||||
|
||||
return (
|
||||
<div className="space-y-8 animate-fade-in pb-10">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h2 className="text-3xl font-bold tracking-tight text-white flex items-center gap-3">
|
||||
Geographic Traffic
|
||||
Geo Traffic
|
||||
{isLoading && <Loader2 className="w-5 h-5 animate-spin text-primary" />}
|
||||
</h2>
|
||||
<p className="text-muted-foreground mt-1">Visualize data flow and activity across the globe.</p>
|
||||
<p className="text-muted-foreground mt-1">Geographic distribution of inbound and outbound traffic by country.</p>
|
||||
</div>
|
||||
<HelpTrigger pageId="geography" />
|
||||
</div>
|
||||
|
||||
<UniversalFilters
|
||||
|
||||
@@ -14,6 +14,7 @@ import { Loader2, Bitcoin, Shield, Server, Lock, AlertTriangle, Key, Globe, Netw
|
||||
import { DeviceDetailModal } from "@/components/ui/DeviceDetailModal";
|
||||
import { TimestampCell } from "@/components/ui/TimestampCell";
|
||||
import { fmtBytes } from "@/lib/utils";
|
||||
import { HelpTrigger } from "@/components/help/HelpTrigger";
|
||||
|
||||
export default function IntelligencePage() {
|
||||
const [mounted, setMounted] = useState(false);
|
||||
@@ -370,11 +371,15 @@ export default function IntelligencePage() {
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-2xl font-bold tracking-tight text-white flex items-center gap-3">
|
||||
Threat Intelligence Feeds
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h2 className="text-3xl font-bold tracking-tight text-white flex items-center gap-3">
|
||||
Threat Intelligence
|
||||
{loadingStats && <Loader2 className="w-5 h-5 animate-spin text-muted-foreground" />}
|
||||
</h2>
|
||||
<p className="text-muted-foreground mt-1">Deep threat intelligence feeds and security detections.</p>
|
||||
</div>
|
||||
<HelpTrigger pageId="intelligence" />
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/Card";
|
||||
import { DropdownFilterSelect } from "@/components/ui/DropdownFilterSelect";
|
||||
import { Loader2, Search, AppWindow, HelpCircle, ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight, X, Info, Tag, Box, Shield, Server } from "lucide-react";
|
||||
|
||||
import { HelpTrigger } from "@/components/help/HelpTrigger";
|
||||
|
||||
export default function LookupPage() {
|
||||
const [mounted, setMounted] = useState(false);
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
@@ -54,14 +56,17 @@ export default function LookupPage() {
|
||||
|
||||
return (
|
||||
<div className="space-y-6 animate-fade-in pb-10">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold text-white tracking-tight flex items-center gap-3">
|
||||
Application Database
|
||||
{isLoading && <Loader2 className="w-5 h-5 animate-spin text-primary" />}
|
||||
</h1>
|
||||
<p className="text-slate-400 mt-2">
|
||||
Search BackOne's extensive classification database of over 2,500+ apps, protocols, and services.
|
||||
</p>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold text-white tracking-tight flex items-center gap-3">
|
||||
App Lookup
|
||||
{isLoading && <Loader2 className="w-5 h-5 animate-spin text-primary" />}
|
||||
</h1>
|
||||
<p className="text-slate-400 mt-2">
|
||||
Search BackOne's extensive classification database of over 2,500+ apps, protocols, and services.
|
||||
</p>
|
||||
</div>
|
||||
<HelpTrigger pageId="lookup" />
|
||||
</div>
|
||||
|
||||
{/* Search & Filter Bar */}
|
||||
|
||||
@@ -12,6 +12,8 @@ import {
|
||||
import { IpDetails } from "@/components/ui/IpDetails";
|
||||
import { RemoteIpDetailModal } from "@/components/ui/RemoteIpDetailModal";
|
||||
|
||||
import { HelpTrigger } from "@/components/help/HelpTrigger";
|
||||
|
||||
export default function NetworkInfrastructurePage() {
|
||||
const [selectedRemoteIp, setSelectedRemoteIp] = useState<string | null>(null);
|
||||
|
||||
@@ -42,9 +44,12 @@ export default function NetworkInfrastructurePage() {
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold text-white tracking-tight">Network Infrastructure</h1>
|
||||
<p className="text-slate-400 mt-2">Physical, logical, and geographic network topologies.</p>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold text-white tracking-tight">Network Topology</h1>
|
||||
<p className="text-slate-400 mt-2">Physical, logical, and geographic network topologies.</p>
|
||||
</div>
|
||||
<HelpTrigger pageId="network-infrastructure" />
|
||||
</div>
|
||||
|
||||
<Tabs>
|
||||
|
||||
@@ -13,6 +13,7 @@ import { useAppCategories, useContinents } from "@/lib/api-with-context";
|
||||
import { fmtBytes } from "@/lib/utils";
|
||||
import { UniversalFilters, useUniversalFilterState, FilterConfig } from "@/components/ui/UniversalFilters";
|
||||
import { CategoryDetailPanel } from "@/components/network/CategoryDetailPanel";
|
||||
import { HelpTrigger } from "@/components/help/HelpTrigger";
|
||||
|
||||
const COLORS = ['#58a6ff', '#3fb950', '#f0883e', '#bc8cff', '#f85149'];
|
||||
|
||||
@@ -90,6 +91,7 @@ export default function NetworkIntelligencePage() {
|
||||
</h2>
|
||||
<p className="text-muted-foreground mt-1">Deep packet inspection analytics and geography.</p>
|
||||
</div>
|
||||
<HelpTrigger pageId="network-intelligence" />
|
||||
</div>
|
||||
|
||||
<UniversalFilters
|
||||
|
||||
@@ -11,6 +11,7 @@ import TlsVersionsChart from "@/components/security-audit/TlsVersionsChart";
|
||||
import TlsTables from "@/components/security-audit/TlsTables";
|
||||
import SslSanTable from "@/components/security-audit/SslSanTable";
|
||||
import { UniversalFilters, useUniversalFilterState, FilterConfig } from "@/components/ui/UniversalFilters";
|
||||
import { HelpTrigger } from "@/components/help/HelpTrigger";
|
||||
|
||||
export default function SecurityAuditPage() {
|
||||
const [mounted, setMounted] = useState(false);
|
||||
@@ -53,11 +54,14 @@ export default function SecurityAuditPage() {
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<h2 className="text-2xl font-bold text-white tracking-tight">Security & Encryption Audit</h2>
|
||||
<p className="text-sm text-slate-400 mt-1">
|
||||
Monitor TLS versions distribution, cipher suites, active certificate properties, and device risk profiles.
|
||||
</p>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h2 className="text-3xl font-bold text-white tracking-tight">Encryption Audit</h2>
|
||||
<p className="text-sm text-slate-400 mt-1">
|
||||
Monitor TLS versions distribution, cipher suites, active certificate properties, and device risk profiles.
|
||||
</p>
|
||||
</div>
|
||||
<HelpTrigger pageId="security-audit" />
|
||||
</div>
|
||||
|
||||
<UniversalFilters
|
||||
|
||||
@@ -13,6 +13,7 @@ import { ThreatFilters } from "@/components/threats/ThreatFilters";
|
||||
import { ThreatRecommendationsDrawer } from "@/components/threats/ThreatRecommendationsDrawer";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
import { formatAppLabel } from "@/lib/utils";
|
||||
import { HelpTrigger } from "@/components/help/HelpTrigger";
|
||||
|
||||
// ─── ThreatsContent ───────────────────────────────────────────────────────────
|
||||
function ThreatsContent() {
|
||||
@@ -215,14 +216,17 @@ function ThreatsContent() {
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h2 className="text-3xl font-bold tracking-tight text-white flex items-center gap-3">
|
||||
Threat Intelligence
|
||||
Detected Threats
|
||||
{threats.isLoading && <Loader2 className="w-5 h-5 animate-spin text-primary" />}
|
||||
</h2>
|
||||
<p className="text-muted-foreground mt-1">Monitor and respond to network security threats.</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 text-sm font-medium text-emerald-400 bg-emerald-500/10 border border-emerald-500/20 px-4 py-2 rounded-lg shadow-[0_0_15px_rgba(16,185,129,0.1)]">
|
||||
<ShieldCheck className="h-4 w-4" />
|
||||
<span>Active Monitoring</span>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex items-center gap-2 text-sm font-medium text-emerald-400 bg-emerald-500/10 border border-emerald-500/20 px-4 py-2 rounded-lg shadow-[0_0_15px_rgba(16,185,129,0.1)]">
|
||||
<ShieldCheck className="h-4 w-4" />
|
||||
<span>Active Monitoring</span>
|
||||
</div>
|
||||
<HelpTrigger pageId="threats" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in new issue
Block a user