EVIDENCE-LED PROSPECTING
Good morning, there ✦
Your pipeline has 0 prospects ready for review.
REVIEW REQUIRED
diff --git a/apps/api/app/main.py b/apps/api/app/main.py index b6c53df..7df7f5f 100644 --- a/apps/api/app/main.py +++ b/apps/api/app/main.py @@ -1362,6 +1362,7 @@ class ApiHandler(BaseHTTPRequestHandler): item=row_json(raw); meta=adapter_meta.get(item.get("source_code") or item.get("kind"), {}) try: config=json.loads(raw["config_json"] or "{}") except (TypeError,ValueError): config={} + if not meta and config.get("provider"): meta=adapter_meta.get(str(config.get("provider")).lower(), {}) try: policy=json.loads(raw["policy_json"] or "{}") except (TypeError,ValueError): policy={} credential_exists = bool(db.execute("SELECT 1 FROM source_credentials WHERE source_id=? AND organization_id=? AND provider=? AND key_name=?", (raw["id"], org, "google_places", "api_key")).fetchone()) @@ -1402,7 +1403,7 @@ class ApiHandler(BaseHTTPRequestHandler): name=str(payload.get('name','')).strip(); requested=str(payload.get('source_code') or payload.get('kind','')).strip().lower(); config=payload.get('config',{}) provider_kinds={'openstreetmap','wikidata','common_crawl'} kind='approved_directory' if requested in provider_kinds else requested - source_code=requested + source_code=str(config.get('provider','')).strip().lower() if requested == 'approved_directory' and str(config.get('provider','')).strip().lower() in {'openstreetmap','wikidata','common_crawl'} else requested if not name or requested not in ('csv','manual','google_places','bing_local','approved_directory','openstreetmap','wikidata','common_crawl','public_website','permitted_social','ct_logs','dns','rdap') or not isinstance(config,dict):return self.send_json(400,{"error":"invalid_source"}) if contains_secret(config):return self.send_json(400,{"error":"secret_not_permitted"}) try: diff --git a/apps/api/app/sources.py b/apps/api/app/sources.py index 78e1066..eeb6ab7 100644 --- a/apps/api/app/sources.py +++ b/apps/api/app/sources.py @@ -418,4 +418,4 @@ def available_adapters() -> list[dict[str, object]]: "available": bool(getattr(cls, "available", False)), "optional": bool(getattr(cls, "optional", False)), "requires_credentials": bool(getattr(cls, "requires_credentials", False))} - for cls in ADAPTERS.values()] + for cls in ADAPTERS.values() if cls.source_code != "approved_directory"] diff --git a/apps/api/tests/test_sources_phase5.py b/apps/api/tests/test_sources_phase5.py index 9313be4..84a4bcc 100644 --- a/apps/api/tests/test_sources_phase5.py +++ b/apps/api/tests/test_sources_phase5.py @@ -12,8 +12,9 @@ class SourceAdapterTests(unittest.TestCase): for code in ('bing_local', 'permitted_social'): self.assertFalse(catalog[code]['available'], code) self.assertTrue(catalog[code]['optional'], code) - self.assertTrue(catalog['approved_directory']['available']) - self.assertFalse(catalog['approved_directory']['optional']) + for code in ('openstreetmap','wikidata','common_crawl'): + self.assertTrue(catalog[code]['available'], code) + self.assertFalse(catalog[code]['optional'], code) self.assertTrue(catalog['google_places']['available']) self.assertTrue(catalog['google_places']['optional']) diff --git a/apps/web/app.js b/apps/web/app.js index 3e57561..012d71a 100644 --- a/apps/web/app.js +++ b/apps/web/app.js @@ -330,7 +330,7 @@ $('interactionForm').addEventListener('submit',saveInteraction);$('suppressionForm').addEventListener('submit',addSuppression);$('aiProviderForm').addEventListener('submit',saveAiProviderSettings);$('aiProvider').addEventListener('change',updateAiProviderForm);$('aiProviderRefreshBtn').addEventListener('click',loadAiProviderSettings);$('testAiProviderBtn').addEventListener('click',testAiProviderConnection);$('crmRefreshBtn').addEventListener('click',()=>{loadCrmPipeline();loadInteractions(selectedId);});$('reportsRefreshBtn').addEventListener('click',loadReports);$('suppressionRefreshBtn').addEventListener('click',loadSuppressions);$('pipelineViewToggle').addEventListener('click',()=>{crmListMode=!crmListMode;$('pipelineViewToggle').textContent=crmListMode?'▦ Board view':'☷ List view';$('pipelineViewToggle').setAttribute('aria-pressed',String(crmListMode));renderPipeline();});$('pipelineBoard').addEventListener('click',e=>{const selectButton=e.target.closest?.('[data-crm-select]');if(selectButton){selectedId=Number(selectButton.dataset.crmSelect);selectProspect(selectedId);loadInteractions(selectedId);$('crmActivity').scrollIntoView({behavior:'smooth',block:'start'});}const stageButton=e.target.closest?.('[data-crm-save-stage]');if(stageButton)saveCrmStage(stageButton.dataset.crmSaveStage);if(e.target.id==='retryCrmBtn')loadCrmPipeline();if(e.target.id==='retryInteractionsBtn'&&selectedId)loadInteractions(selectedId);});$('suppressionState').addEventListener('change',e=>{const input=e.target.closest?.('[data-suppression-id]');if(input){if(input.checked)selectedSuppressionIds.add(String(input.dataset.suppressionId));else selectedSuppressionIds.delete(String(input.dataset.suppressionId));updateSuppressionSelection();}});$('suppressionState').addEventListener('click',e=>{const button=e.target.closest?.('[data-remove-suppression]');if(button)removeSuppression(button.dataset.removeSuppression);if(e.target.id==='retrySuppressionsBtn')loadSuppressions();});$('selectAllSuppressions').addEventListener('change',e=>{suppressions.forEach(item=>e.target.checked?selectedSuppressionIds.add(String(item.id)):selectedSuppressionIds.delete(String(item.id)));renderSuppressions();});$('bulkReviewSuppressionsBtn').addEventListener('click',bulkReviewSuppressions);$('discoveryWorkspace').addEventListener('click',e=>{const action=e.target.closest?.('[data-run-action]');if(action){const run=discoveryRuns.find(item=>String(item.id)===String(selectedDiscoveryRunId));discoveryAction(action.dataset.runAction,run);}}); $('aiProviderForm').addEventListener('submit',saveAiProviderSettings);$('aiProvider').addEventListener('change',updateAiProviderForm);$('aiProviderRefreshBtn').addEventListener('click',loadAiProviderSettings);$('testAiProviderBtn').addEventListener('click',testAiProviderConnection);$('crmRefreshBtn').addEventListener('click',()=>{loadCrmPipeline();loadInteractions(selectedId);});$('reportsRefreshBtn').addEventListener('click',loadReports);$('suppressionRefreshBtn').addEventListener('click',loadSuppressions);$('pipelineViewToggle').addEventListener('click',()=>{crmListMode=!crmListMode;$('pipelineViewToggle').textContent=crmListMode?'▦ Board view':'☷ List view';$('pipelineViewToggle').setAttribute('aria-pressed',String(crmListMode));renderPipeline();});$('pipelineBoard').addEventListener('click',e=>{const selectButton=e.target.closest?.('[data-crm-select]');if(selectButton){selectedId=Number(selectButton.dataset.crmSelect);selectProspect(selectedId);loadInteractions(selectedId);$('crmActivity').scrollIntoView({behavior:'smooth',block:'start'});}const stageButton=e.target.closest?.('[data-crm-save-stage]');if(stageButton)saveCrmStage(stageButton.dataset.crmSaveStage);if(e.target.id==='retryCrmBtn')loadCrmPipeline();if(e.target.id==='retryInteractionsBtn'&&selectedId)loadInteractions(selectedId);});$('suppressionState').addEventListener('change',e=>{const input=e.target.closest?.('[data-suppression-id]');if(input){if(input.checked)selectedSuppressionIds.add(String(input.dataset.suppressionId));else selectedSuppressionIds.delete(String(input.dataset.suppressionId));updateSuppressionSelection();}});$('suppressionState').addEventListener('click',e=>{const button=e.target.closest?.('[data-remove-suppression]');if(button)removeSuppression(button.dataset.removeSuppression);if(e.target.id==='retrySuppressionsBtn')loadSuppressions();});$('selectAllSuppressions').addEventListener('change',e=>{suppressions.forEach(item=>e.target.checked?selectedSuppressionIds.add(String(item.id)):selectedSuppressionIds.delete(String(item.id)));renderSuppressions();});$('bulkReviewSuppressionsBtn').addEventListener('click',bulkReviewSuppressions);$('outreachPolicyRefreshBtn').addEventListener('click',loadProviderPolicy); const viewMap = {dashboard:'dashboard', explorer:'prospects', add:'add', discoveryWorkspace:'discovery', jobs:'jobs', sources:'sources', crmPipeline:'crm', crmActivity:'crm', crmReports:'crm', suppressionCenter:'settings', outreachSettings:'settings', aiProviderSettings:'settings', scoreRules:'dashboard'}; - function activateView(view) { document.body.dataset.view = view; document.querySelectorAll('.content > section').forEach(section => section.classList.toggle('view-active', viewMap[section.id] === view)); window.scrollTo({top:0, behavior:'smooth'}); } + function activateView(view) { document.body.dataset.view = view; document.querySelectorAll('.content > section').forEach(section => section.classList.toggle('view-active', viewMap[section.id] === view)); const labels = {dashboard:'Dashboard', prospects:'Prospect explorer', add:'Add prospects', discovery:'Discovery runs', jobs:'Jobs', sources:'Sources', crm:'CRM pipeline', settings:'Settings'}; const page = document.getElementById('topbarPage'); if (page) page.textContent = labels[view] || 'Workspace'; window.scrollTo({top:0, behavior:'smooth'}); } document.body.dataset.view = 'dashboard'; const sourceSetup = document.querySelector('.source-config-panel'); if (sourceSetup) { diff --git a/apps/web/asset-manifest.json b/apps/web/asset-manifest.json index f9d228d..4f6281f 100644 --- a/apps/web/asset-manifest.json +++ b/apps/web/asset-manifest.json @@ -1,6 +1,6 @@ { "schema": 1, - "version": "phase-26", + "version": "phase-27", "entrypoints": [ "config.js", "app.js", @@ -13,10 +13,10 @@ "healthz" ], "integrity": { - "config.js": "sha256-036e9b1a2d16cf89ffc1cb23f22aab71608b1330e8323d2d42a6c6b86051698c", - "app.js": "sha256-44809719afe72cd0ddc30819b3c73f36019319bfbda4e59d62055fd040b5c6c0", - "styles.css": "sha256-a9fd194b001c0de98775bcf5fbba5da676ccfdd607a889eae84bd30a54c15e08", - "index.html": "sha256-f48882419575ac49c389f07ba25791115981330a1dd623ce3c21b026a0dedd3c", + "config.js": "sha256-95293871c068b38098cead4af5de4b17ee505a0b051b9379567a716dc5364490", + "app.js": "sha256-3bd0215c904f7a8b0ebce3b96c799944880a3ce123694e3680db4516b690e490", + "styles.css": "sha256-ba90290ab11e82a6b2639dfd70d1e74502c1cacb2b26cf1db92b45beb67ac03f", + "index.html": "sha256-f5d2ab03e5c676f8af8a9bfd201e6d4fb3bfb19ba10098e93eae5680122fa2cc", "health.html": "sha256-c352a6f37aa24628cfc8d5709a70ff2d94181d192ed5fe00916cca9378a61d81", "error.html": "sha256-f3cc28d2dfc9e8af112d0257c6ee47b9e9146e5da8590a754dd589bf43702aaf", "healthz": "sha256-dc51b8c96c2d745df3bd5590d990230a482fd247123599548e0632fdbf97fc22" diff --git a/apps/web/config.js b/apps/web/config.js index feb5584..264ef09 100644 --- a/apps/web/config.js +++ b/apps/web/config.js @@ -1,5 +1,5 @@ /* Public, non-secret runtime configuration. Replace this file at deploy time if needed. */ window.__PROSPECT_CONFIG__ = Object.freeze({ apiBase: '', - assetVersion: 'phase-26' + assetVersion: 'phase-27' }); diff --git a/apps/web/index.html b/apps/web/index.html index 033b9c9..052e9d6 100644 --- a/apps/web/index.html +++ b/apps/web/index.html @@ -5,7 +5,7 @@
EVIDENCE-LED PROSPECTING
Your pipeline has 0 prospects ready for review.
REVIEW REQUIRED