---
title: "Search"
canonical: "https://support.appfire.com/page/search/"
format: markdown
---
# Search Appfire Documentation

Search  body, .card p, .card h3, .kb-card p, .kb-card h3, .card-excerpt, .results-count, .meta-space, .sidebar-heading, .space-name, .card-title, .hint, .meta, .name { font-weight: 700 !important; } .card-title { font-size: 16px !important; } .card-excerpt { font-size: 13px !important; } \*, \*::before, \*::after { box-sizing: border-box; margin: 0; padding: 0; } /\* Kill any extra space Refined adds around the page content \*/ html, body { height: auto !important; min-height: 0 !important; background: rgba(10,10,14,1) !important; } .page-shell { min-height: 100vh !important; } .le\_element\_html\_content, .le\_element\_type\_html, .rw\_content, .le\_sections, .rw\_section { background: rgba(10,10,14,1) !important; } /\* Kill Refined's wrapper padding \*/ .le\_element\_html\_content, .le\_element\_type\_html, .rw\_content, .le\_sections, \[class\*="le\_element"\], \[class\*="le\_section"\], section.le\_section, .le\_page, .le\_page\_content, section, .rw\_section { padding-bottom: 0 !important; margin-bottom: 0 !important; } :root { --font: "area", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; --bg: #0b0f16; --surface: rgba(12,17,28,.9); --border: rgba(215,222,234,.14); --border-strong: rgba(215,222,234,.26); --text: #ffffff; --text-muted: rgba(215,222,234,.55); --accent: #397BFF; --shadow-sm: 0 2px 8px rgba(0,0,0,.18); --shadow-md: 0 8px 28px rgba(0,0,0,.35); --radius: 18px; --sidebar-w: 320px; --color-ac: #397BFF; --color-adc: #A78BFA; --color-ms: #FF8A5B; --color-sf: #63E6E2; --color-sl: #FFE08A; --color-mo: #6875f5; --color-sei: #22C55E; --color-skb: #F97316; } html, body { font-family: var(--font); background: rgba(10,10,14,1); color: #fff; line-height: 1.5; } .page-shell { display: flex; flex-direction: column; font-size: 14px; } /\* Topbar \*/ .topbar { background: transparent; border: none; padding: 12px 48px; display: flex; align-items: center; gap: 24px; position: sticky; top: 0; z-index: 100; } .topbar-label { font-size: 14px; font-weight: 700; color: rgba(255,255,255,.6); letter-spacing: .1em; text-transform: ; white-space: nowrap; flex-shrink: 0; } .search-wrap { flex: 1 !important; display: flex !important; align-items: center !important; border: 1px solid #fff !important; border-radius: 999px !important; overflow: hidden !important; background: rgba(10,10,14,1) !important; transition: border-color .15s; } .search-wrap:focus-within { border-color: var(--border-strong); } .search-icon { flex-shrink: 0; margin: 0 10px 0 16px; color: rgba(255,255,255,.5); pointer-events: none; } .search-input { flex: 1; height: 44px; padding: 0; border: none; background: transparent; font-family: var(--font); font-size: 15px; color: #fff; outline: none; min-width: 0; } .search-input::placeholder { color: rgba(255,255,255,.4); } .search-clear { flex-shrink: 0; margin: 0 6px; background: none; border: none; cursor: pointer; color: rgba(255,255,255,.5); padding: 4px; border-radius: 50%; display: none; align-items: center; justify-content: center; transition: color .15s; } .search-clear:hover { color: #fff; } .search-clear.visible { display: flex; } .search-enter { flex-shrink: 0; height: 44px; padding: 0 20px; background: transparent; border: none; border-left: 1px solid rgba(255,255,255,.15); color: rgba(255,255,255,.5); font-size: 12px; font-weight: 600; font-family: var(--font); letter-spacing: .05em; cursor: pointer; white-space: nowrap; transition: color .15s; display: flex; align-items: center; } .search-enter:hover { color: #fff; } /\* Layout \*/ .body-layout { display: flex; width: 100%; padding: 32px 48px 24px; gap: 36px; align-items: flex-start; min-height: 0; } /\* Sidebar \*/ .sidebar { width: var(--sidebar-w); flex-shrink: 0; position: sticky; top: 96px; display: flex; flex-direction: column; gap: 12px; align-self: flex-start; overflow: hidden; } .sidebar-section { background: rgba(10,10,14,1); border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; box-shadow: var(--shadow-sm); } .sidebar-heading { padding: 11px 16px; font-size: 11px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: rgba(255,255,255,.6); border-bottom: 1px solid var(--border); display: flex; justify-content: space-between; align-items: center; } .sidebar-clear { font-size: 11px; font-weight: 600; color: var(--accent); cursor: pointer; text-transform: none; letter-spacing: 0; background: none; border: none; padding: 0; display: none; } .sidebar-clear.visible { display: block; } .sidebar-clear:hover { text-decoration: underline; } /\* Checkboxes \*/ .filter-cb { appearance: none; width: 16px; height: 16px; border: 1px solid var(--border); border-radius: 4px; background: rgba(215,222,234,.06); flex-shrink: 0; cursor: pointer; transition: border-color .12s, background .12s; position: relative; } .filter-cb:checked { background: var(--accent); border-color: var(--accent); } .filter-cb:checked::after { content: ''; position: absolute; left: 4px; top: 2px; width: 6px; height: 4px; border-left: 1.5px solid white; border-bottom: 1.5px solid white; transform: rotate(-45deg); } /\* Platform list \*/ .platform-list { list-style: none; padding: 4px 0; } .platform-item label { display: flex; align-items: center; gap: 9px; padding: 7px 16px; cursor: pointer; color: #fff; font-size: 13px; font-weight: 800; user-select: none; transition: color .12s; } .platform-item label:hover { color: #fff; } .platform-item input\[type="checkbox"\] { position: absolute; opacity: 0; width: 0; height: 0; pointer-events: none; } .platform-dot { width: 14px; height: 14px; min-width: 14px; flex-shrink: 0; border-radius: 2px; border: 1px solid #4466FF; background: transparent; transition: background .15s ease; } .platform-item input\[type="checkbox"\]:checked ~ .platform-dot { background: #4466FF; background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 10 8' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 4l3 3 5-6' stroke='%23fff' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: center; background-size: 9px 7px; } /\* Space list \*/ .space-list { list-style: none; max-height: 380px; overflow-y: auto; scrollbar-width: thin; scrollbar-color: var(--border) transparent; } .space-list::-webkit-scrollbar { width: 4px; } .space-list::-webkit-scrollbar-thumb { background: rgba(215,222,234,.2); border-radius: 2px; } .space-item label { display: flex; align-items: center; gap: 9px; padding: 7px 16px; cursor: pointer; color: #fff; font-size: 13px; font-weight: 400; user-select: none; transition: color .12s; } .space-item label:hover { color: #fff; } .space-item input\[type="checkbox"\] { position: absolute; opacity: 0; width: 0; height: 0; pointer-events: none; } .space-check { width: 14px; height: 14px; min-width: 14px; flex-shrink: 0; border-radius: 2px; border: 1px solid #4466FF; background: transparent; transition: background .15s ease; } .space-item input\[type="checkbox"\]:checked ~ .space-check { background: #4466FF; background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 10 8' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 4l3 3 5-6' stroke='%23fff' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: center; background-size: 9px 7px; } .space-item input\[type="checkbox"\]:checked ~ .space-check + .space-name { color: #fff; } .space-name { flex: 1; line-height: 1.3; } .sidebar-loading { padding: 14px 16px; font-size: 12px; color: rgba(255,255,255,.6); display: flex; align-items: center; gap: 8px; } .mini-spinner { width: 12px; height: 12px; border: 1.5px solid var(--border); border-top-color: var(--accent); border-radius: 50%; animation: spin .7s linear infinite; flex-shrink: 0; } /\* Main \*/ .main { flex: 1; min-width: 0; } .results-meta { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; min-height: 24px; flex-wrap: wrap; gap: 8px; } .space-banner { display: flex; align-items: center; gap: 10px; padding: 10px 16px; margin-bottom: 16px; background: rgba(57,123,255,.12); border: 1px solid rgba(57,123,255,.35); border-radius: 8px; font-size: 13px; color: #fff; } .space-banner-icon { font-size: 15px; flex-shrink: 0; } .space-banner-text { flex: 1; } .space-banner-text strong { color: #6fa3ff; } .space-banner-expand { background: none; border: 1px solid rgba(57,123,255,.45); border-radius: 5px; color: #6fa3ff; font-size: 12px; font-weight: 600; padding: 4px 10px; cursor: pointer; white-space: nowrap; transition: background .15s, color .15s; font-family: var(--font); } .space-banner-expand:hover { background: rgba(57,123,255,.2); color: #fff; } .results-count { font-size: 13px; color: rgba(255,255,255,.6); } .results-count strong { color: #fff; font-weight: 700; } .active-filters { display: flex; gap: 6px; flex-wrap: wrap; } .filter-tag { display: inline-flex; align-items: center; gap: 6px; padding: 4px 12px; background: rgba(57,123,255,.15); color: var(--accent); border-radius: 999px; font-size: 12px; font-weight: 600; cursor: pointer; border: 1px solid rgba(57,123,255,.3); transition: background .12s; } .filter-tag:hover { background: rgba(57,123,255,.25); } /\* Cards \*/ .results-list { display: flex; flex-direction: column; gap: 20px; } .result-card.external-card { border-color: rgba(34,197,94,.25); } .result-card.external-card:hover { border-color: rgba(34,197,94,.5); } .external-badge { font-size: 10px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: #22C55E; background: rgba(34,197,94,.12); border: 1px solid rgba(34,197,94,.3); border-radius: 4px; padding: 2px 6px; margin-left: 8px; vertical-align: middle; } .result-card { background: #121213; border: 1px solid #5c5b5e; border-radius: var(--radius); padding: 20px; text-decoration: none; color: inherit; display: block; transition: border-color .15s, box-shadow .15s, transform .15s; box-shadow: var(--shadow-sm); animation: fadeSlideIn .2s ease both; backdrop-filter: blur(6px); } .result-card:hover { border-color: var(--border-strong); box-shadow: var(--shadow-md); transform: translateY(-3px); } @keyframes fadeSlideIn { from { opacity:0; transform:translateY(6px); } to { opacity:1; transform:translateY(0); } } .card-header { display: flex; align-items: flex-start; gap: 10px; margin-bottom: 6px; } .card-icon { width: 18px; height: 18px; flex-shrink: 0; margin-top: 2px; color: rgba(255,255,255,.6); } .card-title { font-size: 15px; font-weight: 700; color: #fff; line-height: 1.3; flex: 1; letter-spacing: -.01em; } .card-title mark { background: #336fe6; color: #fff; border-radius: 2px; padding: 0 2px; } .card-excerpt { font-size: 13px; color: rgba(215,222,234,.65); line-height: 1.6; margin-bottom: 12px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; } .card-excerpt mark { background: #336fe6; color: #fff; border-radius: 2px; padding: 0 2px; } .card-meta { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; } .meta-badge { display: inline-flex; align-items: center; font-size: 11px; font-weight: 600; color: rgba(255,255,255,.6); background: rgba(215,222,234,.08); padding: 3px 9px; border-radius: 999px; } .meta-sep { color: var(--border-strong); font-size: 11px; } .meta-space { font-size: 12px; font-weight: 600; color: rgba(255,255,255,.6); } /\* Platform tags \*/ .platform-badge { display: inline-flex; align-items: center; font-size: 11px; font-weight: 600; padding: 3px 9px; border-radius: 999px; border: 1px solid; background: transparent; letter-spacing: .01em; color: #fff !important;} .pb-ac { border-color: var(--color-ac); color: var(--color-ac); } .pb-adc { border-color: var(--color-adc); color: var(--color-adc); } .pb-ms { border-color: var(--color-ms); color: var(--color-ms); } .pb-sf { border-color: var(--color-sf); color: var(--color-sf); } .pb-sl { border-color: var(--color-sl); color: var(--color-sl); } .pb-mo { border-color: var(--color-mo); color: var(--color-mo); } .pb-sei { border-color: var(--color-sei); color: var(--color-sei); } .pb-skb { border-color: var(--color-skb); color: var(--color-skb); } .result-card:hover .pb-ac { background: rgba(57,123,255,.1); } .result-card:hover .pb-adc { background: rgba(167,139,250,.1); } .result-card:hover .pb-ms { background: rgba(255,138,91,.1); } .result-card:hover .pb-sf { background: rgba(99,230,226,.1); } .result-card:hover .pb-sl { background: rgba(255,224,138,.1); } .result-card:hover .pb-mo { background: rgba(104,117,245,.1); } .result-card:hover .pb-sei { background: rgba(34,197,94,.1); } .result-card:hover .pb-skb { background: rgba(249,115,22,.1); } /\* States \*/ .state-box { padding: 24px 24px; text-align: center; color: rgba(255,255,255,.6); } .state-box svg { margin-bottom: 16px; opacity: .3; } .state-box h3 { font-size: 16px; font-weight: 700; color: #fff; margin-bottom: 6px; } .state-box p { font-size: 13px; max-width: 320px; margin: 0 auto; } .spinner { width: 28px; height: 28px; border: 2px solid var(--border); border-top-color: var(--accent); border-radius: 50%; animation: spin .7s linear infinite; margin: 0 auto 16px; } @keyframes spin { to { transform: rotate(360deg); } } .load-more-wrap { text-align: center; margin-top: 20px; } .load-more-btn { padding: 9px 28px; background: rgba(215,222,234,.08); border: 1px solid var(--border); border-radius: 999px; font-family: var(--font); font-size: 13px; font-weight: 700; color: rgba(255,255,255,.6); cursor: pointer; transition: border-color .15s, color .15s, background .15s, transform .12s; } .load-more-btn:hover { border-color: var(--border-strong); color: #fff; background: rgba(215,222,234,.12); transform: translateY(-1px); } @media (max-width: 720px) { .body-layout { flex-direction: column; padding: 16px; gap: 16px; } .sidebar { width: 100%; position: static; } .space-list { max-height: 200px; } .topbar { padding: 0 16px; } } /\* ── Related Questions Panel ── \*/ .rq-panel { position: fixed; top: 60px; right: -420px; width: 420px; height: calc(100vh - 60px); background: #0e1219; border-left: 1px solid rgba(215,222,234,.14); z-index: 1000; display: flex; flex-direction: column; transition: right .3s cubic-bezier(.4,0,.2,1); box-shadow: -8px 0 32px rgba(0,0,0,.4); } .rq-panel.open { right: 0; } .rq-panel-header { display: flex; align-items: center; justify-content: space-between; padding: 18px 20px; border-bottom: 1px solid rgba(215,222,234,.1); flex-shrink: 0; } .rq-panel-title { font-size: 13px; font-weight: 700; color: #fff; letter-spacing: .04em; text-transform: uppercase; display: flex; align-items: center; gap: 8px; } .rq-panel-title svg { color: #6fa3ff; } .rq-panel-close { background: none; border: none; color: rgba(255,255,255,.5); cursor: pointer; padding: 4px; border-radius: 4px; transition: color .15s; display: flex; align-items: center; } .rq-panel-close:hover { color: #fff; } .rq-panel-body { flex: 1; overflow-y: auto; padding: 20px; display: flex; flex-direction: column; gap: 12px; } .rq-question-btn { width: 100%; text-align: left; background: rgba(215,222,234,.05); border: 1px solid rgba(215,222,234,.1); border-radius: 8px; padding: 12px 14px; color: #fff; font-size: 13px; font-family: var(--font); cursor: pointer; transition: background .15s, border-color .15s; line-height: 1.4; } .rq-question-btn:hover { background: rgba(57,123,255,.12); border-color: rgba(57,123,255,.35); color: #fff; } .rq-question-btn.active { background: rgba(57,123,255,.15); border-color: rgba(57,123,255,.5); } .rq-answer { background: rgba(57,123,255,.07); border: 1px solid rgba(57,123,255,.2); border-radius: 8px; padding: 14px; font-size: 13px; color: rgba(255,255,255,.85); line-height: 1.6; display: none; margin-top: -4px; } .rq-answer.visible { display: block; } .rq-answer-loading { display: flex; align-items: center; gap: 8px; color: rgba(255,255,255,.5); font-size: 13px; } .rq-answer-loading .spinner { width: 14px; height: 14px; border: 2px solid rgba(255,255,255,.15); border-top-color: #6fa3ff; border-radius: 50%; animation: spin .7s linear infinite; flex-shrink: 0; } .rq-answer-text { margin-bottom: 10px; line-height: 1.6; } .rq-answer-refs { display: flex; flex-direction: column; gap: 6px; margin-top: 10px; border-top: 1px solid rgba(215,222,234,.12); padding-top: 10px; } .rq-answer-ref { display: flex; align-items: center; gap: 7px; font-size: 12px; font-weight: 600; color: #6fa3ff !important; text-decoration: none !important; padding: 6px 10px; border-radius: 6px; background: rgba(57,123,255,.07); border: 1px solid rgba(57,123,255,.15); transition: background .15s, border-color .15s; line-height: 1.4; } .rq-answer-ref:hover { background: rgba(57,123,255,.15); border-color: rgba(57,123,255,.35); color: #fff !important; } .rq-answer-ref svg { flex-shrink: 0; opacity: 0.6; } .rq-skeleton { height: 52px; background: rgba(215,222,234,.06); border-radius: 8px; animation: pulse 1.4s ease-in-out infinite; } @keyframes pulse { 0%,100% { opacity:.4 } 50% { opacity:.8 } } /\* Explore AI button \*/ .explore-ai-btn { display: none; align-items: center; gap: 7px; padding: 12px 24px; background: #336fe6; border: 1px solid #336fe6; border-radius: 60px; color: #fff; font-size: 14px; font-weight: 600; font-family: var(--font); cursor: pointer; transition: background .15s, border-color .15s; margin-bottom: 16px; white-space: nowrap; } .explore-ai-btn:hover { background: #2256c5; border-color: #2256c5; color: #fff; } .explore-ai-btn.visible { display: flex; } .explore-ai-btn svg { flex-shrink: 0; } .rq-overlay { display: none; position: fixed; inset: 0; z-index: 999; } .rq-overlay.visible { display: block; }

 Enter

Platform Clear

📁 Searching in: Search all spaces

Explore related questions

### Start searching

Type a keyword above to search across all documentation spaces.

Load more results

Explore related questions

// ── Platform config ────────────────────────────────────────────── const EXTERNAL\_APPS = \[ { name: 'JXL', description: 'JXL for Jira — spreadsheet-style issue editor', url: 'https://jxl.app/docs/guide/demo/', platforms: \['atlassian-cloud', 'atlassian-dc'\], keywords: \['jxl', 'spreadsheet', 'issue editor'\] }, \]; const PLATFORMS = \[ { id:'atlassian-cloud', label:'Atlassian Cloud', color:'#397BFF', badgeClass:'pb-ac' }, { id:'atlassian-dc', label:'Atlassian Data Center', color:'#A78BFA', badgeClass:'pb-adc' }, { id:'slack', label:'Slack', color:'#FFE08A', badgeClass:'pb-sl' }, { id:'microsoft', label:'Microsoft', color:'#FF8A5B', badgeClass:'pb-ms' }, { id:'monday', label:'monday.com', color:'#6875f5', badgeClass:'pb-mo' }, { id:'SEI', label:'Software Engineering Intelligence', color:'#22C55E', badgeClass:'pb-sei' }, { id:'salesforce', label:'Salesforce', color:'#63E6E2', badgeClass:'pb-sf' }, { id:'support-kb', label:'Support Knowledge Base', color:'#F97316', badgeClass:'pb-skb' }, \]; const ACRONYM\_MAP = { "JMWE":"Jira Misc Workflow Extensions","JMCF":"Jira Misc Custom Fields","JSU":"JSU Automation Suite", "CMJ":"Configuration Manager for Jira","JXL":"JXL","HTML":"HTML for Confluence", "SQL":"SQL for Confluence","JCLI":"Jira Command Line Interface","BCLI":"Bamboo Command Line Interface", "SCLI":"Bitbucket Command Line Interface","CSOAP":"Confluence Command Line Interface", "SIL":"SIL Engine Power Suite","LM":"LaTeX Math","LML":"LaTeX Math Lite", "MARKDOWN":"Markdown for Confluence","PP":"Planning Poker","POLL":"Polls for Confluence", "NH":"Numbered Headings","NC":"Numbered Captions","PCJ":"Project Configurator for Jira", "ICJ":"Integrity Check for Jira","FB":"Flow Board","PA":"Power Admin for Jira", "PE":"Prometheus Exporter","ABTB":"Agile Board Template Builder","CPT":"Copy Page Tree", "CACHE":"Cache for Confluence","CHAT":"Chat for Jira Service Management", "GRAPH":"Charts Graphs for Bitbucket","HED":"Hedge Risk Management", "SNIP":"Snippets for Bitbucket","YACC":"Yet Another Commit Checker", "UTIL":"Power Utilities for Jira","SPACE":"Spacetree for Confluence", "SOURCE":"Source Editor for Confluence","EDITOR":"Power Editor for Bitbucket", "TFS4JIRA":"TFS4JIRA Azure DevOps","ANNOUNCE":"Announcer","ENH":"Easy Numbered Headings", "FOX":"Foxly","OCTO":"Octo","RUN":"Run Self-Service Reports","CR":"Canned Responses Pro", "NEWS":"News Teaser for Confluence","JENK":"Webhook Jenkins for Bitbucket", "AIP":"Assets Inventory Plugin for Jira","CRU":"Crucible Review Hook", "TTS":"Time to SLA","TTSC":"Time to SLA","XL":"Excel for Confluence", "SPM":"BigPicture PPM and Strategic Portfolio Management","ME":"MultiExcerpt","JMWEC":"Jira Misc Workflow Extensions", "JMCFC":"Jira Misc Custom Fields","JSUCLOUD":"JSU Automation Suite", "JQLSEARCH":"JQL Search Extensions for Jira","JPP":"Agile Poker for Jira", "JIFS":"Jira Integration Slack","JIFMT":"Microsoft Teams Integration Jira", "JCPP":"Clone Plus for Jira","JEPC":"Enhancer Plugin for Jira", "JEP":"Enhancer Plugin for Jira","HFS":"HelpDesk Slack Support", "HFMT":"HelpDesk Microsoft Teams","GFJ":"Gaia for Jira","GCC":"Google Calendar Jira", "GMFC":"GitHub Macros for Confluence","EASYF":"Easy Forms for Confluence", "EIFJC":"Easy Integrations for Jira","EI4J":"Easy Integrations for Jira", "DFS":"Docs Slack Confluence","DELGROUPS":"Delegated Group Management", "DADMIN":"Delegated Project Admin","PCFJ":"Delegated Project Creator for Jira", "DBCF":"Power Database Fields","CSOT":"Create on Transition for Jira", "CSFJIRA":"Connector for Salesforce Jira","COPYSP":"Copy Space for Confluence", "CTFCC":"Composition Tabs for Confluence","C4J":"Comala Canvas for Jira", "CBCCL":"Comala Boards for Confluence","CDALS":"Comala Document Approval", "CDCCL":"Comala Document Control","CDMC":"Comala Document Management", "CPCL":"Comala Publishing","CRCCL":"Comala Read Confirmations", "AIPC":"Assets Inventory Plugin for Jira","ART":"Reports Timesheets for Jira", "AW":"Autowatch for Jira","APBCFJ":"Power BI Connector for Jira", "ATCFJ":"Tableau Connector Pro for Jira","CCLI":"Run CLI Actions in Confluence", "JCLIP":"Run CLI Actions in Jira","CCSFCONFC":"Connector Salesforce Confluence", "CFGDCS":"Connector Google Drive Confluence","CMSP":"Macro Security for Confluence", "HTMLM":"HTML Macro for Confluence","ILV":"Issue Matrix for Jira", "IMC":"Issue Matrix for Jira","IMG":"Image Slider for Confluence", "KCFPRO":"Power Custom Fields for Jira","LINC":"Linking for Confluence", "LINS":"Linking for Confluence","OFJ":"OKR for Jira", "PAFC":"Page Approval for Confluence","PAFS":"Page Approval for Confluence", "PDGR":"Power Dashboards Reports Gadgets","PSCONF":"Power Scripts for Confluence", "PSJC":"Power Scripts Jira Workflow Automation","REPS":"Reporting for Confluence", "RFC":"Reporting for Confluence","RFCDOC":"Rich Filters for Jira Dashboards", "RFP":"Rich Filters for Jira Dashboards","RFPDF":"Rich Filters PDF Reports for Jira", "RFSD":"Rich Filters Service Management Dashboards", "RFTT":"Rich Filters Time Tracking Dashboards", "SCAFC":"Scaffolding Forms Templates for Confluence", "SCAFS":"Scaffolding Forms Templates for Confluence","SCRP":"Scripting for Confluence", "SECC":"Security Encryption for Confluence","SECS":"Security Encryption for Confluence", "SFJSDC":"Contact Views Salesforce JSM","SFPUBC":"Publisher Confluence Salesforce", "SILTEMPO":"SIL Tempo Connector","SRTFJ":"Swanly Portfolio Roadmaps", "SRV":"Surveys for Jira","SURVOTE":"Survey Vote Macros", "TBL":"Advanced Tables for Confluence","VISC":"Visibility for Confluence", "VISS":"Visibility for Confluence","7TFJ":"7pace Timetracker for Jira", "7TFM":"7pace Timetracker for monday","SPM":"BigPicture PPM and Strategic Portfolio Management", "ScrumPrint":"Agile Cards Print Issues from Jira","dataplane":"Dataplane Reports for Jira", "atdc":"Advanced Tables for Confluence", }; const FUZZY\_MAP = { "bigpicture":"BigPicture","powerscripts":"Power Scripts", "powercustomfields":"Power Custom Fields","powerutilities":"Power Utilities", "poweradmin":"Power Admin","powerdashboards":"Power Dashboards", "powerdatabase":"Power Database","powereditor":"Power Editor", "powersalesforce":"Power Salesforce","powerbi":"Power BI", "helpdesk":"HelpDesk+","timetosla":"Time to SLA", "advancedtables":"Advanced Tables","richfilters":"Rich Filters", "scaffolding":"Scaffolding Forms","comalaboards":"Comala Boards", "comalacanvas":"Comala Canvas","comalaDocument":"Comala Document", "comalapublishing":"Comala Publishing","dashboardhub":"Dashboard Hub Pro", "jqlsearch":"JQL Search Extensions","multiexcerpt":"MultiExcerpt", "pageapproval":"Page Approval","projectconfigurator":"Project Configurator", "configurationmanager":"Configuration Manager for Jira", }; function expandAcronym(query) { const trimmed = query.trim(); const upper = trimmed.toUpperCase(); for (const \[key, val\] of Object.entries(ACRONYM\_MAP)) { if (key.toUpperCase() === upper) return val; } const normalized = trimmed.toLowerCase().replace(/\[\\s\\-\_\]+/g, ''); if (FUZZY\_MAP\[normalized\]) return FUZZY\_MAP\[normalized\]; return trimmed; } const SPACE\_PLATFORM\_MAP = { "7TFA":\["microsoft"\], "7TFJ":\["atlassian-cloud"\], "7TFM":\["monday"\], "477986818":\["atlassian-dc","salesforce"\], "ABTB":\["atlassian-dc"\], "ACLI":\["atlassian-cloud"\], "ADEFJC":\["atlassian-cloud"\], "AHP":\["atlassian-dc"\], "AIP":\["atlassian-dc"\], "AIPC":\["atlassian-cloud"\], "ANNOUNCE":\["atlassian-cloud","atlassian-dc"\], "APBCFJ":\["atlassian-cloud","atlassian-dc","microsoft"\], "ART":\["atlassian-cloud","atlassian-dc"\], "ATCFJ":\["atlassian-cloud","atlassian-dc"\], "AW":\["atlassian-cloud"\], "BCCLI":\["atlassian-dc"\], "C4J":\["atlassian-cloud","atlassian-dc"\], "CACHE":\["atlassian-dc"\], "CBCCL":\["atlassian-cloud"\], "CBCSL":\["atlassian-dc"\], "CCLI":\["atlassian-dc"\], "CCSFCONFC":\["atlassian-cloud","salesforce"\], "CDACL":\["atlassian-cloud"\], "CDALS":\["atlassian-dc"\], "CDCCL":\["atlassian-cloud"\], "CDMC":\["atlassian-cloud"\], "CDML":\["atlassian-dc"\], "CDS":\["atlassian-dc"\], "CFGDCS":\["atlassian-dc"\], "CHAT":\["atlassian-cloud","atlassian-dc"\], "CLSL":\["atlassian-dc"\], "CMJ":\["atlassian-dc"\], "CMJC":\["atlassian-cloud"\], "CMSP":\["atlassian-dc"\], "CMT":\["atlassian-cloud"\], "COMALACDCLS":\["atlassian-dc"\], "COMALACM":\["atlassian-dc"\], "COPYSP":\["atlassian-cloud"\], "CPCL":\["atlassian-cloud"\], "CPT":\["atlassian-cloud","atlassian-dc"\], "CR":\["atlassian-cloud"\], "CRCCL":\["atlassian-cloud"\], "CRU":\["atlassian-dc"\], "CSFJIRA":\["atlassian-cloud","salesforce"\], "CSOAP":\["atlassian-cloud","atlassian-dc"\], "CSOT":\["atlassian-cloud","atlassian-dc"\], "CT":\["atlassian-dc"\], "CTFCC":\["atlassian-cloud"\], "CTFCSM":\["atlassian-dc"\], "CVP":\["atlassian-dc","microsoft"\], "CW":\["atlassian-dc"\], "DADMIN":\["atlassian-dc"\], "DELGROUPS":\["atlassian-dc"\], "DLP":\["atlassian-dc"\], "BPEdc":\["atlassian-dc"\], "BGdc":\["atlassian-dc"\], "BGc":\["atlassian-cloud"\], "BTdc":\["atlassian-dc"\], "BTc":\["atlassian-cloud"\], "E2F":\["atlassian-dc"\], "EASYF":\["atlassian-dc"\], "EDITOR":\["atlassian-dc"\], "EI4J":\["atlassian-dc"\], "EIFJC":\["atlassian-cloud"\], "ENH":\["atlassian-cloud","atlassian-dc"\], "ESF":\["atlassian-cloud","atlassian-dc"\], "FB":\["atlassian-dc"\], "FD":\["SEI"\], "FOX":\["atlassian-cloud"\], "GCC":\["atlassian-cloud"\], "GFJ":\["atlassian-dc"\], "GMFC":\["atlassian-cloud","atlassian-dc"\], "GRAPH":\["atlassian-dc"\], "GVIZ":\["atlassian-cloud","atlassian-dc"\], "HED":\["atlassian-cloud"\], "HFMT":\["atlassian-cloud","atlassian-dc","microsoft"\], "HFS":\["atlassian-cloud","atlassian-dc","slack"\], "HTML":\["atlassian-cloud","atlassian-dc"\], "HTMLM":\["atlassian-cloud"\], "IC":\["atlassian-cloud","atlassian-dc"\], "ICJ":\["atlassian-dc"\], "ILV":\["atlassian-dc"\], "IMC":\["atlassian-cloud"\], "IMG":\["atlassian-cloud","atlassian-dc"\], "JCLI":\["atlassian-cloud","atlassian-dc"\], "JCLIP":\["atlassian-dc"\], "JCPP":\["atlassian-cloud","atlassian-dc"\], "JENK":\["atlassian-dc"\], "JEP":\["atlassian-dc"\], "JEPC":\["atlassian-cloud"\], "JIFMT":\["atlassian-cloud","atlassian-dc","microsoft"\], "JIFS":\["atlassian-cloud","atlassian-dc","slack"\], "JMCF":\["atlassian-dc"\], "JMCFC":\["atlassian-cloud"\], "JMWE":\["atlassian-dc"\], "JMWEC":\["atlassian-cloud"\], "JPP":\["atlassian-cloud","atlassian-dc"\], "JQLSEARCH":\["atlassian-cloud","atlassian-dc"\], "JSU":\["atlassian-dc"\], "JSUCLOUD":\["atlassian-cloud"\], "LF":\["atlassian-cloud"\], "LINC":\["atlassian-cloud"\], "LINS":\["atlassian-dc"\], "LM":\["atlassian-cloud","atlassian-dc"\], "MARK":\["atlassian-cloud","atlassian-dc"\], "MARKDOWN":\["atlassian-cloud","atlassian-dc"\], "ME":\["atlassian-cloud","atlassian-dc"\], "NC":\["atlassian-cloud","atlassian-dc"\], "NEWS":\["atlassian-cloud","atlassian-dc"\], "NH":\["atlassian-cloud","atlassian-dc"\], "OCTO":\["atlassian-cloud"\], "OFJ":\["atlassian-cloud"\], "PA":\["atlassian-dc"\], "PAFC":\["atlassian-cloud"\], "PAFS":\["atlassian-dc"\], "PAGE":\["atlassian-dc"\], "PC":\["atlassian-dc"\], "PCFC":\["atlassian-cloud"\], "PCFJ":\["atlassian-cloud","atlassian-dc"\], "PE":\["atlassian-dc"\], "POKERADO":\["microsoft"\], "POLL":\["atlassian-cloud","atlassian-dc"\], "PP":\["atlassian-cloud","atlassian-dc"\], "PSCONF":\["atlassian-dc"\], "PSJ":\["atlassian-dc"\], "PSJC":\["atlassian-cloud"\], "RDD":\["atlassian-cloud","atlassian-dc"\], "REPS":\["atlassian-dc"\], "RFC":\["atlassian-cloud"\], "RFCDOC":\["atlassian-cloud"\], "RFP":\["atlassian-dc"\], "RFPDF":\["atlassian-dc"\], "RFSD":\["atlassian-dc"\], "RFTT":\["atlassian-dc"\], "RUN":\["atlassian-dc"\], "SCAFC":\["atlassian-cloud"\], "SCAFS":\["atlassian-dc"\], "SCC":\["atlassian-dc"\], "SCRP":\["atlassian-dc"\], "SECC":\["atlassian-cloud"\], "SECS":\["atlassian-dc"\], "SFJSDC":\["salesforce","atlassian-cloud"\], "SFPUBC":\["atlassian-cloud","salesforce"\], "SNIP":\["atlassian-dc"\], "SOURCE":\["atlassian-cloud","atlassian-dc"\], "SPACE":\["atlassian-dc"\], "SPM":\["atlassian-cloud"\], "SQL":\["atlassian-cloud","atlassian-dc"\], "SRTFJ":\["atlassian-cloud"\], "SRV":\["atlassian-cloud","atlassian-dc"\], "SSO":\["atlassian-dc"\], "SUPPORT":\["support-kb"\], "SURVOTE":\["atlassian-dc"\], "ScrumPrint":\["atlassian-cloud","atlassian-dc"\], "TBL":\["atlassian-cloud"\], "TFS4JIRA":\["atlassian-cloud","atlassian-dc","microsoft"\], "TJC":\["atlassian-cloud"\], "TTS":\["atlassian-dc"\], "TTSC":\["atlassian-cloud"\], "UTIL":\["atlassian-dc"\], "VISC":\["atlassian-cloud"\], "VISS":\["atlassian-dc"\], "XL":\["atlassian-cloud","atlassian-dc"\], "YACC":\["atlassian-dc"\], "atdc":\["atlassian-dc"\], "dataplane":\["atlassian-dc"\], "SUPPORT":\["support-kb"\], }; const BASE\_URL = window.location.origin; const PAGE\_SIZE = 20; let allSpaces = \[\]; let selectedSpaces = new Set(); let selectedPlatforms = new Set(); let currentQuery = ''; let currentRawQuery = ''; let currentStart = 0; let totalResults = 0; let isLoading = false; let debounceTimer = null; async function init() { buildPlatformFilter(); allSpaces = Object.keys(SPACE\_PLATFORM\_MAP) .map(k => ({ key: k, name: SPACE\_NAME\_MAP\[k\] || k, platforms: SPACE\_PLATFORM\_MAP\[k\] })) .sort((a, b) => a.name.localeCompare(b.name)); renderSpaceList(); loadSpaces(); bindEvents(); var urlParams = new URLSearchParams(window.location.search); var q = urlParams.get('q') || ''; var incomingSpace = urlParams.get('space') || ''; if (incomingSpace && SPACE\_PLATFORM\_MAP\[incomingSpace\]) { selectedSpaces.add(incomingSpace); renderSpaceList(); document.getElementById('spaceClear').classList.add('visible'); var bannerSpaceName = SPACE\_NAME\_MAP\[incomingSpace\] || incomingSpace; document.getElementById('spaceBannerName').textContent = bannerSpaceName; document.getElementById('spaceBanner').style.display = 'flex'; document.getElementById('spaceBannerExpand').addEventListener('click', function() { selectedSpaces.clear(); renderSpaceList(); document.getElementById('spaceClear').classList.remove('visible'); document.getElementById('spaceBanner').style.display = 'none'; if (currentQuery) triggerSearch(currentQuery, true); }); } if (q) { document.getElementById('searchInput').value = q; document.getElementById('searchClear').classList.add('visible'); triggerSearch(q, true, true); } } const SPACE\_NAME\_MAP = { "7TFA":"7pace Timetracker", "7TFJ":"7pace Timetracker", "7TFM":"7pace Timetracker", "477986818":"Connector for Salesforce & Jira", "ABTB":"Agile Board Template Builder for Jira", "ACLI":"Appfire Command Line Interface (CLI)", "ADEFJC":"Database Exporter for Jira Cloud", "AHP":"Comala Publishing", "AIP":"Assets and Inventory Plugin for Jira", "AIPC":"Assets and Inventory Plugin for Jira", "ANNOUNCE":"Announcer Apps", "APBCFJ":"Power BI Jira Connector", "ART":"Reports and Timesheets for Jira", "ATCFJ":"Tableau Connector Pro for Jira", "AW":"Autowatch for Jira", "BCCLI":"Bitbucket Cloud Command Line Interface (CLI)", "C4J":"Comala Canvas for Jira", "CACHE":"Cache for Confluence", "CBCCL":"Comala Boards for Confluence", "CBCSL":"Comala Boards for Confluence", "CCLI":"Run CLI Actions in Confluence", "CCSFCONFC":"Connector for Salesforce & Confluence", "CDACL":"Comala Document Approval", "CDALS":"Comala Document Approval", "CDCCL":"Comala Document Control", "CDMC":"Comala Document Management", "CDML":"Comala Document Management", "CDS":"Collapsible Dashboard Sidebar", "CFGDCS":"Connector for Google Drive & Confluence", "CHAT":"Chat for Jira Service Management", "CLSL":"Comala Lists", "CMJ":"Configuration Manager for Jira (CMJ)", "CMJC":"Configuration Manager for Jira (CMJ)", "CMSP":"Macro Security for Confluence", "CMT":"Configuration Manager Cloud Migration Tool", "COMALACDCLS":"Comala Document Control", "COMALACM":"Comala Metadata", "COPYSP":"Copy Space for Confluence", "CPCL":"Comala Publishing", "CPT":"Copy Page Tree", "CR":"Canned Responses Pro Templates for Jira", "CRCCL":"Comala Read Confirmations", "CRU":"Crucible Review Hook for Bitbucket", "CSFJIRA":"Connector for Salesforce & Jira", "CSOAP":"Confluence Command Line Interface (CLI)", "CSOT":"Create on Transition for Jira", "CT":"Canned Responses Pro Templates for Jira", "CTFCC":"Composition Tabs for Confluence", "CTFCSM":"Composition Tabs for Confluence", "CVP":"Visio for Confluence", "CW":"Update on Transition for Jira", "DADMIN":"Delegated Project Admin Pro for Jira", "DELGROUPS":"Delegated Group Management", "DLP":"BigPicture Data Center", "BPEdc":"BigPicture Enterprise - Strategic Management for Jira", "BGdc":"BigGantt – Gantt Chart for Jira", "BGc":"BigGantt – Gantt Chart for Jira", "BTdc":"BigTemplate – Export to PDF, Word, Excel", "BTc":"BigTemplate – Export to PDF, Word, Excel", "E2F":"SAFe EPIC to Feature Translator for Jira", "EASYF":"Easy Forms for Confluence", "EDITOR":"Power Editor for Bitbucket", "EI4J":"Easy Integrations for Jira", "EIFJC":"Easy Integrations for Jira", "ENH":"Easy Numbered Headings", "ESF":"Electronic Signatures", "FB":"Flow Board", "FD":"Flow", "FOX":"Foxly Project Prioritization", "GCC":"Issue Events: Google Calendar integration for Jira", "GFJ":"Gaia for Jira – Project Template Manager", "GMFC":"Github Macros for Confluence", "GRAPH":"Charts & Graphs for Bitbucket", "GVIZ":"Graphviz Diagrams for Confluence", "HED":"Hedge", "HFMT":"HelpDesk+ for Microsoft Teams", "HFS":"HelpDesk+ for Slack", "HTML":"HTML for Confluence", "HTMLM":"HTML Macro for Confluence Cloud", "IC":"Issue History Collector – See History", "ICJ":"Integrity Check for Jira", "ILV":"Issue Matrix for Jira", "IMC":"Issue Matrix for Jira", "IMG":"Image Slider for Confluence", "JCLI":"Jira Command Line Interface (CLI)", "JCLIP":"Run CLI Actions in Jira", "JCPP":"Clone Plus for Jira", "JENK":"Webhook to Jenkins for Bitbucket", "JEP":"Enhancer Plugin for Jira", "JEPC":"Enhancer Plugin for Jira", "JIFMT":"Integration+ for Microsoft Teams", "JIFS":"Integration+ for Slack", "JMCF":"Jira Misc Custom Fields (JMCF)", "JMCFC":"Jira Misc Custom Fields (JMCF)", "JMWE":"Jira Misc Workflow Extensions (JMWE)", "JMWEC":"Jira Misc Workflow Extensions (JMWE)", "JPP":"Agile Poker for Jira", "JQLSEARCH":"JQL Search Extensions for Jira", "JSU":"JSU Automation Suite for Jira Workflows", "JSUCLOUD":"JSU Automation Suite for Jira Workflows", "LF":"Live Fields for Jira Cloud", "LINC":"Linking for Confluence", "LINS":"Linking for Confluence", "LM":"LaTeX Math", "MARK":"Markdown Extensions for Confluence", "MARKDOWN":"Markdown for Confluence", "ME":"MultiExcerpt", "NC":"Numbered Captions", "NEWS":"News Teaser for Confluence", "NH":"Numbered Headings", "OCTO":"Octo", "OFJ":"OKR for Jira", "PA":"Power Admin", "PAFC":"Page Approval for Confluence", "PAFS":"Page Approval for Confluence", "PAGE":"Pages for Bitbucket", "PC":"Project Configurator for Jira", "PCFC":"Power Custom Fields", "PCFJ":"Delegated Project Creator", "PE":"Prometheus Exporter", "POKERADO":"Planning Poker", "POLL":"Polls for Confluence", "PP":"Planning Poker", "PSCONF":"Power Scripts for Confluence", "PSJ":"Power Scripts for Jira", "PSJC":"Power Scripts for Jira", "RDD":"Dashboard Hub", "REPS":"Reporting for Confluence", "RFC":"Reporting for Confluence", "RFCDOC":"Rich Filters for Jira Dashboards", "RFP":"Rich Filters for Jira Dashboards", "RFPDF":"Rich Filters::PDF Reports for Jira", "RFSD":"Rich Filters::Service Management Dashboards", "RFTT":"Rich Filters::Time Tracking Dashboards", "RUN":"Run Self-Service Reports for Confluence", "SCAFC":"Scaffolding Forms & Templates for Confluence", "SCAFS":"Scaffolding Forms & Templates for Confluence", "SCC":"Secure Content for Confluence", "SCRP":"Scripting for Confluence", "SECC":"Security and Encryption for Confluence", "SECS":"Security and Encryption for Confluence", "SFJSDC":"Contact Views for Salesforce & JSM", "SFPUBC":"Publisher for Confluence Cloud to Salesforce", "SNIP":"Snippets for Bitbucket", "SOURCE":"Source Editor for Confluence", "SPACE":"Spacetree for Confluence", "SPM":"BigPicture PPM and Strategic Portfolio Management", "SQL":"SQL for Confluence (Pro Edition)", "SRTFJ":"Swanly: Portfolio Roadmaps Structure Gantt, Release Timeline", "SRV":"Surveys for Jira – Jira Customer Surveys", "SSO":"Global SSO", "SUPPORT":"Appfire Support Knowledge Base", "SURVOTE":"Survey and Vote Macros", "ScrumPrint":"Agile Cards – Print Issues from Jira", "TBL":"Advanced Tables for Confluence", "TFS4JIRA":"TFS4JIRA Azure DevOps integration", "TJC":"Toggl Integration for Jira", "TTS":"Time to SLA for Jira", "TTSC":"Time to SLA for Jira", "UTIL":"Power Utilities for Jira", "VISC":"Visibility for Confluence", "VISS":"Visibility for Confluence", "XL":"Excel for Confluence", "YACC":"Yet Another Commit Checker", "atdc":"Advanced Tables for Confluence", "dataplane":"Dataplane Reports for Jira", "SUPPORT":"Appfire Support Knowledge Base", }; function spaceName(key, apiName) { if (apiName && apiName !== key && !/^\[A-Z0-9\_\]+$/.test(apiName)) return apiName; return SPACE\_NAME\_MAP\[key\] || apiName || key; } async function loadSpaces() { allSpaces = Object.keys(SPACE\_PLATFORM\_MAP) .map(k => ({ key: k, name: SPACE\_NAME\_MAP\[k\] || k, platforms: SPACE\_PLATFORM\_MAP\[k\] })) .sort((a, b) => a.name.localeCompare(b.name)); renderSpaceList(); } function buildPlatformFilter() { const list = document.getElementById('platformList'); list.innerHTML = PLATFORMS.map(p => \` <li class="platform-item"> <label> <input class="filter-cb" type="checkbox" value="${p.id}"> <span class="platform-dot"></span> <span>${p.label}</span> </label> </li>\`).join(''); list.querySelectorAll('input').forEach(cb => cb.addEventListener('change', () => { cb.checked ? selectedPlatforms.add(cb.value) : selectedPlatforms.delete(cb.value); document.getElementById('platformClear').classList.toggle('visible', selectedPlatforms.size > 0); renderSpaceList(); updateActiveFilters(); if (currentQuery) triggerSearch(currentQuery, true); })); } document.getElementById('platformClear').addEventListener('click', () => { selectedPlatforms.clear(); document.querySelectorAll('#platformList input').forEach(cb => cb.checked = false); document.getElementById('platformClear').classList.remove('visible'); renderSpaceList(); updateActiveFilters(); if (currentQuery) triggerSearch(currentQuery, true); }); function renderSpaceList() { const list = document.getElementById('spaceList'); const visible = selectedPlatforms.size > 0 ? allSpaces.filter(s => s.platforms.some(p => selectedPlatforms.has(p))) : allSpaces; \[...selectedSpaces\].forEach(k => { if (!visible.find(s => s.key === k)) selectedSpaces.delete(k); }); list.innerHTML = visible.map(s => \` <li class="space-item"> <label> <input class="filter-cb" type="checkbox" value="${s.key}" ${selectedSpaces.has(s.key) ? 'checked' : ''}> <span class="space-check"></span> <span class="space-name">${esc(s.name)}</span> </label> </li>\`).join(''); list.querySelectorAll('input').forEach(cb => cb.addEventListener('change', () => { cb.checked ? selectedSpaces.add(cb.value) : selectedSpaces.delete(cb.value); document.getElementById('spaceClear').classList.toggle('visible', selectedSpaces.size > 0); updateActiveFilters(); if (currentQuery) triggerSearch(currentQuery, true); })); document.getElementById('spaceClear').classList.toggle('visible', selectedSpaces.size > 0); } const spaceClearBtn = document.getElementById('spaceClear'); if (spaceClearBtn) spaceClearBtn.addEventListener('click', () => { selectedSpaces.clear(); document.querySelectorAll('#spaceList input').forEach(cb => cb.checked = false); if (spaceClearBtn) spaceClearBtn.classList.remove('visible'); updateActiveFilters(); if (currentQuery) triggerSearch(currentQuery, true); }); function updateActiveFilters() { const container = document.getElementById('activeFilters'); const tags = \[\]; selectedPlatforms.forEach(id => { const p = PLATFORMS.find(x => x.id === id); if (p) tags.push({ label: p.label, type: 'platform', id }); }); selectedSpaces.forEach(key => { const s = allSpaces.find(x => x.key === key); tags.push({ label: s ? s.name : key, type: 'space', id: key }); }); if (!tags.length) { container.innerHTML = ''; return; } container.innerHTML = tags.map(t => \`<span class="filter-tag" data-type="${t.type}" data-id="${esc(t.id)}">${esc(t.label)}<svg width="10" height="10" viewBox="0 0 10 10" fill="none"><path d="M1 1l8 8M9 1L1 9" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg></span>\`).join(''); container.querySelectorAll('.filter-tag').forEach(tag => tag.addEventListener('click', () => { const { type, id } = tag.dataset; if (type === 'platform') { selectedPlatforms.delete(id); const cb = document.querySelector(\`#platformList input\[value="${id}"\]\`); if (cb) cb.checked = false; document.getElementById('platformClear').classList.toggle('visible', selectedPlatforms.size > 0); renderSpaceList(); } else { selectedSpaces.delete(id); const cb = document.querySelector(\`#spaceList input\[value="${id}"\]\`); if (cb) cb.checked = false; document.getElementById('spaceClear').classList.toggle('visible', selectedSpaces.size > 0); } updateActiveFilters(); if (currentQuery) triggerSearch(currentQuery, true); })); } // ── FIX 2: Restore scroll lock that Refined's native search dialog adds ── function restoreScroll() { document.documentElement.style.removeProperty('overflow'); document.body.style.removeProperty('overflow'); document.documentElement.style.removeProperty('height'); document.body.style.removeProperty('height'); } function bindEvents() { const input = document.getElementById('searchInput'); const clearBtn = document.getElementById('searchClear'); input.addEventListener('input', () => { const val = input.value.trim(); clearBtn.classList.toggle('visible', val.length > 0); clearTimeout(debounceTimer); if (!val) { showEmpty(); currentQuery = ''; return; } debounceTimer = setTimeout(() => triggerSearch(val, true, false), 350); }); input.addEventListener('keydown', e => { if (e.key === 'Enter') { clearTimeout(debounceTimer); const val = input.value.trim(); if (val) triggerSearch(val, true, true); } }); // Restore scroll when user clicks away from the search input input.addEventListener('blur', () => { setTimeout(restoreScroll, 50); }); document.getElementById('searchEnter').addEventListener('click', () => { clearTimeout(debounceTimer); const val = input.value.trim(); if (val) triggerSearch(val, true, true); else input.focus(); }); clearBtn.addEventListener('click', () => { input.value = ''; clearBtn.classList.remove('visible'); showEmpty(); currentQuery = ''; input.focus(); restoreScroll(); }); document.getElementById('loadMoreBtn').addEventListener('click', () => { if (currentQuery) fetchResults(currentQuery, currentStart); }); // Also restore scroll on any click outside the search area document.addEventListener('click', e => { if (!e.target.closest('.search-wrap')) { restoreScroll(); } }); } function triggerSearch(query, reset = false, explicit = false) { currentRawQuery = query; query = expandAcronym(query); currentQuery = query; if (reset) { currentStart = 0; totalResults = 0; const btn = document.getElementById('exploreAiBtn'); if (btn) btn.classList.remove('visible'); closeRqPanel(); } fetchResults(query, currentStart, explicit); } async function fetchResults(query, start, explicit = false) { if (isLoading) return; isLoading = true; if (start === 0) showLoading(); let spaceKeys; if (selectedSpaces.size > 0) spaceKeys = \[...selectedSpaces\]; else if (selectedPlatforms.size > 0) spaceKeys = allSpaces.filter(s => s.platforms.some(p => selectedPlatforms.has(p))).map(s => s.key); else spaceKeys = allSpaces.map(s => s.key); if (!spaceKeys.length) { renderResults(\[\], true); updateCount(0, 0); toggleLoadMore(false); isLoading = false; return; } const q = JSON.stringify(query); const cql = \`space.key in (${spaceKeys.map(k => \`"${k}"\`).join(',')}) AND (type in (page,blogpost,embed,folder)) AND (siteSearch ~ ${q})\`; const params = new URLSearchParams({ expand: 'content.space', cql, limit: PAGE\_SIZE, start }); try { const res = await fetch(\`${BASE\_URL}/rest/api/search?${params}\`, { credentials: 'same-origin', headers: { accept: 'application/json' } }); if (!res.ok) throw new Error(); const data = await res.json(); totalResults = data.totalSize || 0; const newStart = start + (data.results?.length || 0); currentStart = newStart; renderResults(data.results || \[\], start === 0); if (start === 0 && data.results && data.results.length > 0) triggerRelatedQuestions(query); updateCount(totalResults, newStart); if (start === 0 && explicit) fireRefinedSearchEvent(currentRawQuery, totalResults); toggleLoadMore(newStart < totalResults); } catch { showError(); } finally { isLoading = false; } } function buildExternalCard(app) { const plat = PLATFORMS.find(p => app.platforms.includes(p.id)); const badge = plat ? \`<span class="platform-badge ${plat.badgeClass}">${plat.label}</span>\` : ''; return \`<a href="${app.url}" class="result-card external-card" target="\_blank" rel="noreferrer"> <div class="card-top"> <span class="type-icon"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><rect x="2" y="2" width="12" height="12" rx="2" stroke="currentColor" stroke-width="1.3"/><path d="M5 6h6M5 8.5h4" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/></svg></span> <span class="card-title">${esc(app.name)}<span class="external-badge">External</span></span> </div> <div class="card-excerpt">${esc(app.description)}</div> <div class="card-meta">${badge}</div> </a>\`; } function getExternalMatches(query) { if (!query) return \[\]; const q = query.toLowerCase(); const raw = (currentRawQuery || '').toLowerCase(); return EXTERNAL\_APPS.filter(app => { const name = app.name.toLowerCase(); return name.includes(q) || name.includes(raw) || app.keywords.some(k => k.includes(q) || q.includes(k) || k.includes(raw) || raw.includes(k)); }); } function renderResults(results, replace) { const area = document.getElementById('resultsArea'); const externalCards = replace ? getExternalMatches(currentQuery).map(buildExternalCard).join('') : ''; if (replace && !results.length && !externalCards) { area.innerHTML = \`<div class="state-box"><svg width="40" height="40" viewBox="0 0 24 24" fill="none"><circle cx="10" cy="10" r="7" stroke="currentColor" stroke-width="1.5"/><path d="M16 16l4 4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg><h3>No results found</h3><p>Try different keywords or remove some filters.</p></div>\`; return; } const cards = results.map((r, i) => buildCard(r, i)).join(''); if (replace) { area.innerHTML = \`<div class="results-list">${externalCards}${cards}</div>\`; } else { area.querySelector('.results-list')?.insertAdjacentHTML('beforeend', cards); } } function buildCard(result, idx) { const content = result.content || {}; const spaceKey = content.space?.key || ''; const sName = content.space?.name || result.resultGlobalContainer?.title || ''; const type = content.type || 'page'; const url = resolveUrl(result); const delay = idx < 10 ? \`animation-delay:${idx\*30}ms\` : ''; const title = hlToMark(result.title || esc(content.title || 'Untitled')); const excerpt = hlToMark(result.excerpt || ''); const platforms = SPACE\_PLATFORM\_MAP\[spaceKey\] || \[\]; const pBadges = platforms.map(pid => { const p = PLATFORMS.find(x => x.id === pid); return p ? \`<span class="platform-badge ${p.badgeClass}">${p.label}</span>\` : ''; }).join(''); return \`<a href="${url}" class="result-card" target="\_top" style="${delay}"> <div class="card-header"><span class="card-icon">${typeIcon(type)}</span><span class="card-title">${title}</span></div> ${excerpt ? \`<div class="card-excerpt">${excerpt}</div>\` : ''} <div class="card-meta"> <span class="meta-badge">${type.charAt(0).toUpperCase()+type.slice(1)}</span> ${sName ? \`<span class="meta-sep">·</span><span class="meta-space">${esc(sName)}</span>\` : ''} ${pBadges ? \`<span class="meta-sep">·</span>${pBadges}\` : ''} </div> </a>\`; } function resolveUrl(result) { const raw = result.url || result.content?.\_links?.webui || ''; if (!raw) return '#'; if (raw.startsWith('http')) return raw; const pm = raw.match(/^\\/spaces\\/(\[^/\]+)\\/pages\\/(\\d+)(\\/.\*)?$/); if (pm) return \`${BASE\_URL}/space/${pm\[1\]}/${pm\[2\]}${pm\[3\]||''}\`; const om = raw.match(/^\\/spaces\\/(\[^/\]+)\\/overview/); if (om) return \`${BASE\_URL}/space/${om\[1\]}\`; const sm = raw.match(/^\\/spaces\\/(\[^/\]+)\\/(.+)$/); if (sm) return \`${BASE\_URL}/space/${sm\[1\]}/${sm\[2\]}\`; return BASE\_URL + raw; } const hlToMark = s => s.replace(/@@@hl@@@/g,'<mark>').replace(/@@@endhl@@@/g,'</mark>'); const typeIcon = t => t==='blogpost' ? \`<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><rect x="2" y="2" width="12" height="12" rx="2" stroke="currentColor" stroke-width="1.3"/><path d="M5 6h6M5 8.5h4" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/></svg>\` : t==='folder' ? \`<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M2 4a1 1 0 011-1h3l1.5 2H13a1 1 0 011 1v5a1 1 0 01-1 1H3a1 1 0 01-1-1V4z" stroke="currentColor" stroke-width="1.3"/></svg>\` : \`<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><rect x="3" y="1" width="10" height="14" rx="1.5" stroke="currentColor" stroke-width="1.3"/><path d="M6 5h4M6 8h4M6 11h2" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/></svg>\`; function updateCount(total, shown) { document.getElementById('resultsCount').innerHTML = total > 0 ? \`Showing <strong>${shown}</strong> of <strong>${total}</strong> result${total!==1?'s':''}\` : ''; } const toggleLoadMore = show => document.getElementById('loadMoreWrap').style.display = show ? 'block' : 'none'; const showLoading = () => { document.getElementById('resultsArea').innerHTML=\`<div class="state-box"><div class="spinner"></div><p>Searching…</p></div>\`; toggleLoadMore(false); document.getElementById('resultsCount').innerHTML=''; }; const showEmpty = () => { document.getElementById('resultsArea').innerHTML=\`<div class="state-box"><svg width="40" height="40" viewBox="0 0 24 24" fill="none"><circle cx="10" cy="10" r="7" stroke="currentColor" stroke-width="1.5"/><path d="M16 16l4 4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg><h3>Start searching</h3><p>Type a keyword above to search across all documentation spaces.</p></div>\`; toggleLoadMore(false); document.getElementById('resultsCount').innerHTML=''; }; const showError = () => { document.getElementById('resultsArea').innerHTML=\`<div class="state-box"><svg width="40" height="40" viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="1.5"/><path d="M12 8v4M12 16h.01" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg><h3>Something went wrong</h3><p>Could not fetch results. Make sure you're logged in and try again.</p></div>\`; }; const esc = s => String(s||'').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;'); // ── Refined Analytics ──────────────────────────────────────────── function fireRefinedSearchEvent(searchTerm, resultCount) { try { fetch('https://api-us.analytics.refined.app/ingest/v1/events', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Api-Key': 'KQBinHCPKZ3qOBG8mjAyk4EqvWa4qBEF28GcdhSk' }, body: JSON.stringify({ eventName: 'CharlieSearchTerm', timestampOrigin: new Date().toISOString(), source: 'charlie\_client', customerId: '22033', customerIdHash: '78f04b12d940ffd1a21cb8d37c9b7dfd2bcc9ea49af8281325b611456616dc5e', accountId: '60e5a9cf4134aa00693db82c', accountIdHash: 'df692b67003d25c9ed22aa7f673711f289c4cae07dee9cbf383e525e1ad46605', data: { searchTerm: searchTerm, searchResults: resultCount, userType: 'USER', currentSearchCategory: 'confluence', searchLocationFilterId: 10633, searchSessionId: crypto.randomUUID(), siteId: 10633, containerId: '104703', searchResultsByCategory: \[ { category: 'recommendedLinks', results: 0 }, { category: 'navigation', results: 0 }, { category: 'confluenceContent', results: resultCount } \] } }) }).catch(() => {}); } catch(e) {} } init(); // Kill Refined's section/wrapper padding around this page (function killPadding() { function strip() { var el = document.querySelector('.page-shell'); while (el && el !== document.body) { el.style.setProperty('padding-bottom', '0', 'important'); el.style.setProperty('margin-bottom', '0', 'important'); el = el.parentElement; } document.body.style.setProperty('padding-bottom', '0', 'important'); document.body.style.setProperty('margin-bottom', '0', 'important'); } strip(); setTimeout(strip, 300); setTimeout(strip, 1000); })(); // ── Related Questions (Refined AI) ── const rqCache = new Map(); var rqCurrentQuery = null; function getRefinedCsrf() { var el = document.querySelector('\[name="csrf-token"\], \[data-csrf\], #csrf-token'); return el ? (el.content || el.value || el.getAttribute('data-csrf') || '') : ''; } function refinedPost(body) { return fetch('/rest/latest/refined-ai/generate-questions', { method: 'POST', credentials: 'same-origin', headers: { 'Content-Type': 'application/json', 'accept': 'application/json', 'csrf-token': getRefinedCsrf() }, body: JSON.stringify({ clientType: 'confluence', browserLanguageCode: navigator.language || 'en', ...body }) }); } async function prefetchAnswer(query, question) { const entry = rqCache.get(query); if (!entry) return; try { const parsed = await fetchAnswer(question, query, entry.sessionId); entry.answers\[question\] = parsed; } catch(e) { entry.answers\[question\] = null; } } async function fetchRelatedQuestions(query) { if (rqCache.has(query)) return rqCache.get(query).questions; try { const res = await refinedPost({ question: query }); if (!res.ok) return null; const data = await res.json(); const sessionId = data.sessionId || null; const questions = \[...data.answer.matchAll(/<question>(\[^<\]+)<\\/question>/g)\].map(m => m\[1\].trim()); if (!questions.length) return null; const entry = { sessionId, questions, answers: {} }; rqCache.set(query, entry); questions.forEach(q => prefetchAnswer(query, q)); return questions; } catch(e) { return null; } } function renderAnswer(el, parsed) { let html = \`<div class="rq-answer-text">${esc(parsed.text).replace(/\\n/g, '<br>')}</div>\`; if (parsed.references && parsed.references.length) { html += \`<div class="rq-answer-refs">\`; parsed.references.forEach(ref => { const url = \`${BASE\_URL}/space/${ref.spaceKey}/${ref.pageId}\`; html += \`<a href="${url}" class="rq-answer-ref" target="\_top"> <svg width="12" height="12" viewBox="0 0 16 16" fill="none"><rect x="3" y="1" width="10" height="14" rx="1.5" stroke="currentColor" stroke-width="1.3"/><path d="M6 5h4M6 8h4M6 11h2" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/></svg> ${esc(ref.title)} </a>\`; }); html += \`</div>\`; } el.innerHTML = html; } async function fetchAnswer(q, originalQuery, sessionId) { const res = await fetch('/rest/latest/refined-ai/query', { method: 'POST', credentials: 'same-origin', headers: { 'Content-Type': 'application/json', 'accept': 'application/json', 'csrf-token': getRefinedCsrf() }, body: JSON.stringify({ question: q, originalQuestion: originalQuery || q, sessionId: sessionId || null, kbArticleReference: null, clientType: 'confluence', browserLanguageCode: navigator.language || 'en' }) }); if (!res.ok) throw new Error(); const text = await res.text(); const refMatch = text.match(/(\\{"references":.\*\\})$/s); const answerText = refMatch ? text.slice(0, refMatch.index).trim() : text.trim(); let references = \[\]; if (refMatch) { try { references = JSON.parse(refMatch\[1\]).references || \[\]; } catch(e) {} } return { text: answerText, references }; } function openRqPanel(query, questions) { const body = document.getElementById('rqBody'); const panel = document.getElementById('rqPanel'); const overlay = document.getElementById('rqOverlay'); if (!body || !panel) return; body.innerHTML = questions.map((q, i) => \` <button class="rq-question-btn" data-idx="${i}" data-q="${esc(q)}">${esc(q)}</button> <div class="rq-answer" id="rq-answer-${i}"></div> \`).join(''); body.querySelectorAll('.rq-question-btn').forEach(btn => { btn.addEventListener('click', async function() { const idx = this.dataset.idx; const q = this.dataset.q; const answerEl = document.getElementById('rq-answer-' + idx); if (!answerEl) return; if (this.classList.contains('active')) { this.classList.remove('active'); answerEl.classList.remove('visible'); return; } body.querySelectorAll('.rq-question-btn').forEach(b => b.classList.remove('active')); body.querySelectorAll('.rq-answer').forEach(a => a.classList.remove('visible')); this.classList.add('active'); answerEl.classList.add('visible'); const entry = rqCache.get(query); const cached = entry && entry.answers\[q\]; if (cached) { renderAnswer(answerEl, cached); return; } answerEl.innerHTML = '<div class="rq-answer-loading"><div class="spinner"></div>Generating answer…</div>'; try { const parsed = await fetchAnswer(q, query, entry ? entry.sessionId : null); if (entry) entry.answers\[q\] = parsed; renderAnswer(answerEl, parsed); } catch(e) { answerEl.textContent = 'Could not load answer. Try searching for this question directly.'; } }); }); panel.classList.add('open'); overlay.classList.add('visible'); } function closeRqPanel() { const panel = document.getElementById('rqPanel'); const overlay = document.getElementById('rqOverlay'); if (panel) panel.classList.remove('open'); if (overlay) overlay.classList.remove('visible'); } // ── FIX 1: Use closest() so clicking the SVG inside the button still works ── document.addEventListener('click', function(e) { if (!e.target) return; if (e.target.closest('#rqClose')) { closeRqPanel(); return; } if (e.target.id === 'rqOverlay') { closeRqPanel(); return; } if (e.target.id === 'exploreAiBtn' || e.target.closest('#exploreAiBtn')) openRqPanelOrLoading(); }); function openRqPanelOrLoading() { const body = document.getElementById('rqBody'); const panel = document.getElementById('rqPanel'); const overlay = document.getElementById('rqOverlay'); if (!body || !panel) return; const query = rqCurrentQuery; const entry = query && rqCache.get(query); if (entry && entry.questions.length) { openRqPanel(query, entry.questions); return; } body.innerHTML = \` <div class="rq-loading"> <div class="rq-skeleton"></div> <div class="rq-skeleton" style="opacity:.7"></div> <div class="rq-skeleton" style="opacity:.5"></div> </div>\`; panel.classList.add('open'); overlay.classList.add('visible'); openRqPanel.\_\_onReady = (q, questions) => { if (panel.classList.contains('open')) openRqPanel(q, questions); }; } async function triggerRelatedQuestions(query) { const btn = document.getElementById('exploreAiBtn'); if (!btn) return; openRqPanel.\_\_onReady = null; rqCurrentQuery = query; btn.classList.add('visible'); const questions = await fetchRelatedQuestions(query); if (rqCurrentQuery !== query) return; if (!questions || !questions.length) { btn.classList.remove('visible'); return; } if (typeof openRqPanel.\_\_onReady === 'function') { openRqPanel.\_\_onReady(query, questions); } }
