124 lines
24 KiB
HTML
124 lines
24 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>ProspectOS · Pipeline intelligence</title>
|
||
<meta name="description" content="Prospect discovery and review dashboard">
|
||
<link rel="stylesheet" href="styles.css?v=phase-15">
|
||
</head>
|
||
<body>
|
||
<section class="login-screen" id="loginScreen" aria-labelledby="loginTitle">
|
||
<div class="login-card">
|
||
<a class="brand login-brand" href="#login" aria-label="ProspectOS home"><span class="brand-mark">✦</span><span>Prospect<span class="brand-light">OS</span></span></a>
|
||
<p class="eyebrow">WORKSPACE ACCESS</p>
|
||
<h1 id="loginTitle">Welcome back</h1>
|
||
<p class="login-subtitle">Sign in to review your evidence-led growth pipeline.</p>
|
||
<form id="loginForm" novalidate>
|
||
<label>Email address<input id="loginEmail" name="email" type="email" autocomplete="username" placeholder="you@company.com" required></label>
|
||
<label>Password<input id="loginPassword" name="password" type="password" autocomplete="current-password" placeholder="Enter your password" required></label>
|
||
<p id="loginMessage" class="form-message" role="alert" aria-live="polite"></p>
|
||
<button class="button primary login-submit" type="submit">Sign in <span aria-hidden="true">→</span></button>
|
||
</form>
|
||
<p class="login-note">Use the credentials configured for your workspace.</p>
|
||
</div>
|
||
</section>
|
||
<div class="app-shell" id="dashboardShell" hidden>
|
||
<aside class="sidebar">
|
||
<a class="brand" href="#top" aria-label="ProspectOS home"><span class="brand-mark">✦</span><span>Prospect<span class="brand-light">OS</span></span></a>
|
||
<nav aria-label="Primary navigation">
|
||
<a class="nav-item active" href="#dashboard"><span>▦</span> Dashboard</a>
|
||
<a class="nav-item" href="#explorer"><span>⌕</span> Prospect explorer</a>
|
||
<a class="nav-item" href="#add"><span>+</span> Add prospects</a>
|
||
<a class="nav-item" href="#jobs" data-nav="jobs"><span>◷</span> Jobs</a>
|
||
<a class="nav-item" href="#sources" data-nav="sources"><span>⌁</span> Sources</a>
|
||
<a class="nav-item" href="#crmPipeline" data-nav="crm"><span>◫</span> CRM pipeline</a>
|
||
<a class="nav-item" href="#crmReports" data-nav="reports"><span>▤</span> Reports</a>
|
||
<a class="nav-item" href="#suppressionCenter" data-nav="suppression"><span>⊘</span> Suppressions</a>
|
||
<a class="nav-item" href="#outreachSettings" data-nav="outreach-settings"><span>⚙</span> Outreach policy</a>
|
||
<a class="nav-item" href="#scoreRules" data-nav="score-rules"><span>◈</span> Score rules</a>
|
||
</nav>
|
||
<div class="sidebar-foot"><div class="live-dot"></div><div><strong>Workspace live</strong><small>Data sync is healthy</small></div></div>
|
||
</aside>
|
||
<main class="main" id="top">
|
||
<header class="topbar"><button class="mobile-menu" id="menuBtn" aria-label="Toggle navigation">☰</button><div class="crumb">Workspace <span>/</span> Growth pipeline</div><div class="top-actions"><span class="api-status" id="apiStatus">● Connecting…</span><span class="user-identity" id="userIdentity"></span><button class="icon-button" aria-label="Notifications">♢</button><button class="logout-button" id="logoutBtn" type="button">Log out</button><div class="avatar" id="userAvatar">?</div></div></header>
|
||
<div class="content">
|
||
<section class="hero" id="dashboard"><div><p class="eyebrow">EVIDENCE-LED PROSPECTING</p><h1>Good morning, Alex <span>✦</span></h1><p class="hero-sub">Your pipeline has <strong id="heroCount">0 prospects</strong> ready for review.</p></div><button class="button primary" data-scroll="#add">+ Add prospect</button></section>
|
||
<section class="metrics" aria-label="Dashboard metrics">
|
||
<a class="metric-card metric-link" data-dashboard-filter="all" href="#explorer"><div class="metric-icon violet">◎</div><div><p>Total prospects</p><h2 id="metricTotal">0</h2><span class="trend neutral">● Current workspace</span></div></a>
|
||
<a class="metric-card metric-link" data-dashboard-filter="review" href="#explorer"><div class="metric-icon amber">◌</div><div><p>Needs review</p><h2 id="metricReview">0</h2><span class="trend neutral">● Human verification</span></div></a>
|
||
<a class="metric-card metric-link" data-dashboard-filter="high" href="#explorer"><div class="metric-icon green">◉</div><div><p>High-fit prospects</p><h2 id="metricHigh">0</h2><span class="trend neutral">● Score 80+</span></div></a>
|
||
<a class="metric-card metric-link" data-dashboard-filter="fresh" href="#explorer"><div class="metric-icon blue">◷</div><div><p>Freshness under 7d</p><h2 id="metricFresh">0%</h2><span class="trend neutral">● Evidence coverage</span></div></a>
|
||
<a class="metric-card metric-link" data-dashboard-filter="suppressed" href="#explorer"><div class="metric-icon violet">⊘</div><div><p>Suppressed</p><h2 id="metricSuppressed">0</h2><span class="trend neutral">● Do not contact</span></div></a>
|
||
</section>
|
||
<section class="score-overview" aria-label="Score overview"><article class="panel score-distribution-panel" id="scoreDistributionPanel" data-smoke="score-distribution"><div class="detail-loading" aria-live="polite">Sign in to load score distribution…</div></article></section>
|
||
<section class="score-rules-section" id="scoreRules" aria-labelledby="scoreRulesTitle"><article class="panel" id="scoreRulesPanel" data-smoke="score-rules"><div class="detail-loading" aria-live="polite">Sign in to load score rules…</div></article></section>
|
||
<section class="workspace-grid" id="explorer">
|
||
<div class="explorer-panel panel"><div class="panel-heading"><div><p class="eyebrow">PIPELINE</p><h2>Prospect explorer</h2></div><button class="button ghost" id="refreshBtn">↻ Refresh</button></div>
|
||
<div class="filters"><label class="search-wrap"><span>⌕</span><input id="searchInput" type="search" placeholder="Search companies, domains, locations…" autocomplete="off"></label><select id="scoreFilter" aria-label="Filter by score"><option value="all">All scores</option><option value="high">High fit · 80+</option><option value="medium">Medium · 60–79</option><option value="low">Low · under 60</option></select><select id="statusFilter" aria-label="Filter by status"><option value="all">All statuses</option><option value="review">Needs review</option><option value="reviewed">Reviewed</option><option value="suppressed">Suppressed</option></select><select id="websiteClassFilter" aria-label="Filter by website class"><option value="all">All website classes</option><option value="business_site">Business site</option><option value="social_profile">Social profile</option><option value="missing">Missing website</option></select><select id="pipelineFilter" aria-label="Filter by pipeline stage"><option value="all">All pipeline stages</option><option value="new">New</option><option value="qualified">Qualified</option><option value="review">Review</option><option value="suppressed">Suppressed</option></select></div>
|
||
<div class="saved-view-controls" data-smoke="saved-views"><form id="savedFilterForm" class="inline-form"><input id="savedFilterName" name="name" placeholder="Save current filters as…" maxlength="80" required><button class="button ghost compact" type="submit">Save view</button></form><select id="savedFilterSelect" aria-label="Load saved view"><option value="">Saved views</option></select><button class="button ghost compact" id="deleteSavedFilterBtn" type="button" disabled>Delete view</button><p id="savedFilterMessage" class="form-message" role="status" aria-live="polite"></p></div>
|
||
<section class="review-queue" data-smoke="review-queue"><div class="queue-heading"><div><p class="eyebrow">OPERATOR QUEUE</p><h3>Review queue <span class="count" id="reviewQueueCount">0</span></h3></div><span class="small-label">Human decision required</span></div><div id="reviewQueueState" class="queue-state" aria-live="polite">Loading review queue…</div><div class="bulk-actions"><label class="checkbox-label"><input id="selectAllReview" type="checkbox"> Select visible</label><span id="selectedReviewCount" class="small-label">0 selected</span><button class="button primary compact" id="bulkVerifyBtn" type="button" disabled>Verify selected</button><button class="button danger compact" id="bulkRejectBtn" type="button" disabled>Reject selected</button></div></section>
|
||
<div class="table-meta"><span id="resultCount">Showing 0 prospects</span><span class="legend"><span class="legend-dot high-dot"></span> High fit <span class="legend-dot review-dot"></span> Needs review</span><label class="page-size">Rows <select id="pageSize" aria-label="Page size"><option>10</option><option>25</option><option>50</option></select></label><button class="button ghost compact" id="nextPageBtn" type="button">Next page →</button></div>
|
||
<div id="explorerState" class="explorer-state" aria-live="polite"></div><div class="table-scroll"><table><thead><tr><th>Company</th><th>Fit score</th><th>Evidence</th><th>Freshness</th><th>Status</th><th></th></tr></thead><tbody id="prospectRows"></tbody></table></div>
|
||
</div>
|
||
<aside class="detail-panel panel" id="detailPanel"><div class="empty-detail"><span class="empty-icon">◒</span><h3>Select a prospect</h3><p>Review evidence, confidence, and eligibility before taking action.</p></div></aside>
|
||
</section>
|
||
<section class="jobs-section" id="jobs" aria-labelledby="jobsTitle">
|
||
<div class="jobs-header panel">
|
||
<div><p class="eyebrow">OPERATIONS</p><h2 id="jobsTitle">Job monitor</h2><p class="muted">Track authenticated workspace jobs and their progress. No job data is shown until the API responds.</p></div>
|
||
<div class="jobs-actions"><button class="button ghost" id="jobsRefreshBtn" type="button">↻ Refresh</button><button class="button primary" id="startDemoJobBtn" type="button">+ Start demo job</button></div>
|
||
</div>
|
||
<div id="jobsMessage" class="jobs-message" role="status" aria-live="polite"></div>
|
||
<div class="job-counts" id="jobCounts" aria-label="Job status counts">
|
||
<article class="job-count queued"><span>Queued</span><strong id="jobCountQueued">—</strong></article><article class="job-count running"><span>Running</span><strong id="jobCountRunning">—</strong></article><article class="job-count succeeded"><span>Succeeded</span><strong id="jobCountSucceeded">—</strong></article><article class="job-count failed"><span>Failed</span><strong id="jobCountFailed">—</strong></article><article class="job-count cancelled"><span>Cancelled</span><strong id="jobCountCancelled">—</strong></article>
|
||
</div>
|
||
<div class="jobs-grid">
|
||
<div class="jobs-list panel"><div class="panel-heading"><div><p class="eyebrow">QUEUE</p><h3>Recent jobs</h3></div><span id="jobsUpdatedAt" class="small-label">Not loaded</span></div><div id="jobsList" class="jobs-list-body"><div class="job-empty">Sign in to load jobs from the workspace.</div></div></div>
|
||
<aside class="job-detail panel" id="jobDetailPanel"><div class="empty-detail"><span class="empty-icon">◷</span><h3>Select a job</h3><p>Inspect progress, structured errors, and the event timeline.</p></div></aside>
|
||
</div>
|
||
</section>
|
||
<section class="sources-section" id="sources" aria-labelledby="sourcesTitle">
|
||
<div class="sources-header panel"><div><p class="eyebrow">GOVERNANCE</p><h2 id="sourcesTitle">Sources</h2><p class="muted">Review source ownership, terms, limits, and health before using discovery.</p></div><button class="button ghost" id="sourcesRefreshBtn" type="button">↻ Refresh</button></div>
|
||
<div class="source-safety" role="note"><strong>Discovery is disabled by default.</strong> No live source is enabled in this workspace. Enable a source only after its terms, owner, rate limit, and health have been reviewed.</div>
|
||
<div id="sourcesMessage" class="sources-message" role="status" aria-live="polite"></div>
|
||
<div class="sources-grid">
|
||
<article class="panel source-config-panel"><div class="panel-heading"><div><p class="eyebrow">CONFIGURATION</p><h3>Add a source</h3></div><span class="small-label">Manual or CSV</span></div><form id="sourceForm"><div class="form-grid"><label>Source name<input name="name" required placeholder="Public business directory"></label><label>Source type<select name="source_type" id="sourceType"><option value="manual">Manual / API</option><option value="csv">CSV upload</option></select></label><label>Source URL <span class="optional">optional</span><input name="url" type="url" placeholder="https://…"></label><label>Terms URL <span class="optional">required for enablement</span><input name="terms_url" type="url" placeholder="https://…/terms"></label><label>Owner<input name="owner" required placeholder="Team or accountable person"></label><label>Rate limit<input name="rate_limit" required placeholder="e.g. 60 requests/hour"></label></div><label class="source-csv-field" id="sourceCsvField" hidden>CSV content<textarea name="csv_content" id="sourceCsvContent" rows="4" placeholder="Paste CSV content; it is sent only when you save this source."></textarea></label><div class="form-footer"><p id="sourceFormMessage" class="form-message" role="status"></p><button class="button primary" type="submit">Save source</button></div></form></article>
|
||
<article class="panel discovery-panel"><div class="panel-heading"><div><p class="eyebrow">DISCOVERY</p><h3>Query a source</h3></div><span class="small-label">No automatic runs</span></div><form id="discoveryForm"><label>Source<select name="source_id" id="discoverySource" required><option value="">Select a source</option></select></label><label>Query<input name="query" required placeholder="e.g. renewable energy firms in Cape Town"></label><label class="checkbox-label"><input type="checkbox" name="dry_run" id="discoveryDryRun" checked> Dry run (preview only)</label><div class="form-footer"><p id="discoveryMessage" class="form-message" role="status"></p><div class="discovery-actions"><button class="button ghost" id="discoveryDryRunBtn" type="submit">Validate query</button><button class="button primary" id="discoveryRunBtn" type="button">Run discovery</button></div></div></form></article>
|
||
</div>
|
||
<div class="sources-list panel"><div class="panel-heading"><div><p class="eyebrow">REGISTRY</p><h3>Configured sources</h3></div><span id="sourcesUpdatedAt" class="small-label">Not loaded</span></div><div id="sourcesList" class="sources-list-body"><div class="source-empty">Sign in to load sources from the workspace.</div></div></div>
|
||
<div class="source-records panel"><div class="panel-heading"><div><p class="eyebrow">RECENT OUTPUT</p><h3>Recent source records</h3></div></div><div id="sourceRecordsList" class="source-records-body"><div class="source-empty">No records loaded.</div></div></div>
|
||
</section>
|
||
<section class="lower-grid" id="add"><article class="panel add-panel"><div class="panel-heading"><div><p class="eyebrow">INTAKE</p><h2>Add a prospect</h2></div><span class="small-label">Manual entry</span></div><form id="addForm"><div class="form-grid"><label>Company name<input required name="name" placeholder="Acme Inc."></label><label>Website <span class="optional">optional</span><input name="website" type="url" placeholder="https://acme.com"></label><label>Location<input name="location" placeholder="Cape Town, ZA"></label><label>Notes <span class="optional">optional</span><input name="description" placeholder="Why this is a fit…"></label></div><div class="form-footer"><p id="formMessage" class="form-message" role="status"></p><button class="button primary" type="submit">Add to review queue</button></div></form></article>
|
||
<article class="panel csv-panel"><div class="panel-heading"><div><p class="eyebrow">BULK INTAKE</p><h2>CSV preview</h2></div><label class="button ghost upload-label" for="csvInput">↑ Choose CSV</label><input id="csvInput" type="file" accept=".csv,text/csv" hidden></div><p class="muted">Preview rows before adding them to your review queue.</p><div id="csvPreview" class="csv-empty"><span>⊞</span><p>No file selected</p><small>CSV stays in your browser until you confirm.</small></div></article></section>
|
||
<section class="crm-section" id="crmPipeline" aria-labelledby="crmPipelineTitle" data-smoke="crm-pipeline">
|
||
<div class="crm-header panel"><div><p class="eyebrow">CRM WORKFLOW</p><h2 id="crmPipelineTitle">Pipeline board</h2><p class="muted">Move prospects through explicit human stages. Stage changes never send outreach.</p></div><div class="crm-actions"><button class="button ghost" id="crmRefreshBtn" type="button">↻ Refresh CRM</button><button class="button ghost" id="pipelineViewToggle" type="button" aria-pressed="false">☷ List view</button></div></div>
|
||
<div class="crm-safety" role="note"><strong>No outreach from this workspace.</strong> Pipeline actions, interactions, and follow-ups are internal CRM records only. Suppressed or unreviewed prospects remain unavailable for contact.</div>
|
||
<p id="crmMessage" class="crm-message" role="status" aria-live="polite"></p>
|
||
<div id="pipelineBoard" class="pipeline-board" aria-live="polite"><div class="detail-loading">Sign in to load the pipeline.</div></div>
|
||
</section>
|
||
<section class="crm-section" id="crmActivity" aria-labelledby="crmActivityTitle" data-smoke="crm-interactions">
|
||
<div class="crm-header panel"><div><p class="eyebrow">RELATIONSHIP HISTORY</p><h2 id="crmActivityTitle">Interactions & follow-ups</h2><p class="muted">Capture outcomes and next steps without contacting anyone.</p></div></div>
|
||
<div class="crm-two-col"><article class="panel interaction-panel"><div id="interactionState" class="detail-loading">Select a prospect to load interactions.</div></article><article class="panel"><div class="panel-heading"><div><p class="eyebrow">ADD RECORD</p><h3>Log an interaction</h3></div><span class="small-label">Internal only</span></div><form id="interactionForm" class="crm-form"><label>Type<select name="type"><option value="note">Note</option><option value="call">Call</option><option value="meeting">Meeting</option><option value="email">Email (record only)</option></select></label><label>Outcome<select name="outcome"><option value="">Choose outcome</option><option value="no_response">No response</option><option value="interested">Interested</option><option value="not_a_fit">Not a fit</option><option value="follow_up">Follow-up requested</option></select></label><label>Follow-up date <span class="optional">optional</span><input name="follow_up_at" type="date"></label><label>Summary<textarea name="summary" rows="4" required placeholder="What happened? Keep this an internal record."></textarea></label><p id="interactionMessage" class="form-message" role="status"></p><button class="button primary" type="submit">Save interaction</button></form></article></div>
|
||
</section>
|
||
<section class="crm-section" id="crmReports" aria-labelledby="crmReportsTitle" data-smoke="crm-reports">
|
||
<div class="crm-header panel"><div><p class="eyebrow">REPORTING</p><h2 id="crmReportsTitle">CRM reports</h2><p class="muted">Tenant-scoped pipeline, outcomes, and activity summaries from the API.</p></div><button class="button ghost" id="reportsRefreshBtn" type="button">↻ Refresh reports</button></div>
|
||
<div class="reports-grid"><article class="panel report-panel" id="pipelineReport"><div class="detail-loading">Loading pipeline report…</div></article><article class="panel report-panel" id="outcomesReport"><div class="detail-loading">Loading outcomes report…</div></article><article class="panel report-panel" id="activityReport"><div class="detail-loading">Loading activity report…</div></article></div>
|
||
</section>
|
||
<section class="crm-section" id="suppressionCenter" aria-labelledby="suppressionTitle" data-smoke="suppression-center">
|
||
<div class="crm-header panel"><div><p class="eyebrow">SAFETY CENTER</p><h2 id="suppressionTitle">Suppression center</h2><p class="muted">Review and maintain tenant-scoped do-not-contact rules.</p></div><button class="button ghost" id="suppressionRefreshBtn" type="button">↻ Refresh suppressions</button></div>
|
||
<div class="suppression-warning" role="alert"><strong>Suppression always wins.</strong> Suppressed contacts and domains cannot be contacted, regardless of score, stage, or interaction outcome.</div>
|
||
<div class="crm-two-col"><article class="panel"><div class="panel-heading"><div><p class="eyebrow">ADD RULE</p><h3>Add suppression</h3></div><span class="small-label">Explicit confirmation required</span></div><form id="suppressionForm" class="crm-form"><label>Kind<select name="kind"><option value="email">Email</option><option value="domain">Domain</option><option value="phone">Phone</option></select></label><label>Value<input name="value" required placeholder="person@example.com"></label><label>Reason <span class="optional">optional</span><input name="reason" placeholder="Customer request / policy"></label><p id="suppressionMessage" class="form-message" role="status"></p><button class="button danger" type="submit">Add suppression</button></form></article><article class="panel"><div class="panel-heading"><div><p class="eyebrow">REGISTER</p><h3>Current suppressions</h3></div><div class="suppression-bulk-actions"><label class="checkbox-label"><input id="selectAllSuppressions" type="checkbox"> Select all</label><button class="button ghost compact" id="bulkReviewSuppressionsBtn" type="button" disabled>Review selected</button></div></div><div id="suppressionState" class="detail-loading">Sign in to load suppressions.</div></article></div>
|
||
</section>
|
||
<section class="crm-section outreach-settings-section" id="outreachSettings" aria-labelledby="outreachSettingsTitle" data-smoke="outreach-provider-policy"><div class="crm-header panel"><div><p class="eyebrow">GOVERNANCE</p><h2 id="outreachSettingsTitle">Outreach provider policy</h2><p class="muted">View approved provider status without exposing credentials or secrets.</p></div><button class="button ghost" id="outreachPolicyRefreshBtn" type="button">↻ Refresh policy</button></div><div class="outreach-settings-safety" role="note"><strong>Sending is disabled by default.</strong> This panel is status-only. Provider configuration never creates a send trigger, and no credentials are displayed.</div><div id="providerPolicyPanel" class="provider-policy-panel" aria-live="polite"><div class="detail-loading">Sign in to load provider policy.</div></div></section>
|
||
<footer><span>ProspectOS</span><span>Evidence-led prospecting · <a href="#explorer">Review queue</a></span></footer>
|
||
</div>
|
||
</main>
|
||
</div>
|
||
<div class="merge-dialog" id="mergeDialog" hidden role="dialog" aria-modal="true" aria-labelledby="mergeDialogTitle">
|
||
<div class="merge-dialog-card"><div class="panel-heading"><div><p class="eyebrow">REVIEW REQUIRED</p><h2 id="mergeDialogTitle">Confirm merge</h2></div><button class="icon-button" id="cancelMergeBtn" type="button" aria-label="Close merge confirmation">×</button></div><p id="mergeDialogCopy"></p><div class="merge-warning"><strong>This action is reversible.</strong> The merge will be recorded in history and can be reversed later.</div><p id="mergeDialogMessage" class="form-message" role="alert" aria-live="polite"></p><div class="merge-dialog-actions"><button class="button ghost" id="cancelMergeBtnSecondary" type="button">Cancel</button><button class="button primary" id="confirmMergeBtn" type="button">Confirm merge</button></div></div>
|
||
</div>
|
||
<script src="config.js?v=phase-15"></script>
|
||
<script src="app.js?v=phase-15"></script>
|
||
</body>
|
||
</html>
|