openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
136 lines • 17.7 kB
JavaScript
import{n as e}from"./rolldown-runtime-8BhlS34s.js";import{qr as t}from"./control-ui-foundation-ZY_Flbbd.js";import{Bn as n,Hn as r,Rn as i,Vn as a,hu as o,lu as s,su as c,uu as l,zn as u}from"./control-ui-core-3P365fbR.js";import{$r as d,Jr as f,Ki as ee,Ur as p,Wi as m,Xi as h,Zi as g,Zr as _,ca as v,ua as te,wi as ne}from"./control-ui-core-CFW9Qtjn.js";import{$ as y,F as b,M as x,X as S,Y as C,Z as w,c as T,nt as E,s as D,ut as O}from"./lit-runtime-P5vbNq6b.js";import{nn as k,rn as A}from"./control-ui-boot-shared-CG9HtEG-.js";import{K as re,q as ie}from"./control-ui-boot-shared-73R4ErOy.js";import{vr as ae,yr as j}from"./control-ui-boot-shared-CcmBeh0v.js";import{n as M,t as N}from"./control-ui-boot-shared-BR12heUA.js";import{mn as P,un as F}from"./control-ui-boot-shared-CApmg5ot.js";import{a as I,i as L,o as R,r as z,t as B}from"./panel-tab-strip-BM8uM2tc.js";import{n as V,t as H}from"./panel-empty-state-BO6bnLg_.js";function U(){return W+=1,`chat-files-content-${W}`}var W,G;function K(){return(K=e((()=>{C(),E(),D(),g(),I(),k(),B(),l(),s(),ae(),W=0,G=class extends c{constructor(...e){super(...e),this.contentId=U(),this.hostedTabsChangeKey=``,this.previews=[],this.activeId=null,this.tabsInHeader=!0,this.browser=S,this.renderDetail=null,this.onSelect=()=>{},this.onClose=()=>{}}get hostedTabs(){let e=this.previews.map(({id:e,label:t,content:n})=>({id:e,label:t,title:n.kind===`file`?n.path:t,icon:j({filename:t,mode:`preview-with-favicon`}),className:n.kind===`loading`?`is-connecting`:void 0}));return this.activeId===null&&e.length?[{id:`browse`,label:o(`chat.sidePanel.files`),icon:h.folder},...e]:e}get activeHostedTabId(){return this.activeId??(this.previews.length?`browse`:null)}get hostedActions(){return y`<button
class="rail-header__action"
type="button"
aria-label=${o(`chat.sidePanel.files`)}
title=${o(`chat.sidePanel.files`)}
=${()=>this.onSelect(null)}
>
${h.folder}
</button>`}selectHostedTab(e){this.onSelect(e===`browse`?null:e)}async closeHostedTab(e){e===`browse`?this.onSelect(this.previews.at(-1)?.id??null):this.onClose(e)}updated(){let e=JSON.stringify([this.activeHostedTabId,o(`chat.sidePanel.files`),this.hostedTabs.map(({id:e,label:t,title:n,className:r})=>[e,t,n,r])]);e!==this.hostedTabsChangeKey&&(this.hostedTabsChangeKey=e,this.dispatchEvent(new CustomEvent(L,{bubbles:!0})))}render(){return y`
${this.tabsInHeader?S:y`<header class="rail-header side-panel__header">
<div class="side-panel__header-tabs">
${z({tabs:this.hostedTabs.map(e=>({...e,domId:`${this.contentId}-tab-${e.id}`,closeLabel:`${o(`browser.closeTab`)}: ${e.label}`})),activeId:this.activeHostedTabId,ariaControls:this.contentId,onSelect:e=>this.selectHostedTab(e),onClose:e=>this.closeHostedTab(e),onNew:()=>this.onSelect(null),newLabel:o(`chat.sidePanel.files`),newControl:this.hostedActions})}
</div>
</header>`}
<div id=${this.contentId} class="chat-files-panel__content">
<div class="chat-files-panel__page" ?hidden=${this.activeId!==null}>${this.browser}</div>
${T(this.previews,e=>e.id,e=>y`
<div class="chat-files-panel__page" ?hidden=${this.activeId!==e.id}>
${e.content.kind===`loading`?A(`files`,o(`common.loading`)):e.content.kind===`unavailable`?y`<div class="callout danger" role="alert">
${e.content.message}
</div>`:this.renderDetail?.(e.content)}
</div>
`)}
</div>
`}},t([O({attribute:!1})],G.prototype,`previews`,void 0),t([O({attribute:!1})],G.prototype,`activeId`,void 0),t([O({type:Boolean})],G.prototype,`tabsInHeader`,void 0),t([O({attribute:!1})],G.prototype,`browser`,void 0),t([O({attribute:!1})],G.prototype,`renderDetail`,void 0),t([O({attribute:!1})],G.prototype,`onSelect`,void 0),t([O({attribute:!1})],G.prototype,`onClose`,void 0),customElements.get(`openclaw-chat-files-panel`)||customElements.define(`openclaw-chat-files-panel`,G)})))()}function q(e){return y`<resizable-divider
${b(e.onElement??(()=>{}))}
class=${e.className??S}
.splitRatio=${e.splitRatio}
.minRatio=${e.minRatio??.4}
.maxRatio=${e.maxRatio??.7}
.measureRatio=${e.measureRatio}
.measureSize=${e.measureSize}
.label=${e.label}
.orientation=${e.orientation}
=${e.onDragover??(()=>{})}
=${e.onDrop??(()=>{})}
=${e.onResize}
></resizable-divider>`}function J(){return(J=e((()=>{C(),x()})))()}function Y(e,t){let n=e.find(e=>e.slot===t);if(!n)throw Error(`Missing sidebar panel definition for ${t}`);return n}function X(e,t=!1){return y`
<span slot=${t?`icon`:S} class="side-panel-type-option__icon" aria-hidden="true"
>${e.icon}</span
>
<span class="side-panel-type-option__label">${e.label}</span>
${e.shortcut?ee(e.shortcut,{slot:t?`details`:void 0,className:`side-panel-type-option__shortcut`}):S}
`}var Z,Q;function $(){return($=e((()=>{K(),C(),E(),D(),te(),g(),m(),H(),I(),B(),d(),ne(),l(),s(),re(),N(),P(),J(),Z=[[`browser`,p,{open:!0,newTab:!0}],[`link-reader`,f,{open:!0,newTab:!0}],[`terminal`,_,{open:!0,newSession:!0}]],Q=class extends c{constructor(...e){super(...e),this.panelIdPrefix=``,this.layout={columns:[]},this.panelDefinitions=ie(),this.panelTemplates={},this.panelActions={},this.availableSlots=[],this.callbacks=null,this.narrow=!1,this.availableWidth=0,this.previousGeometry=``,this.geometryFrame=null,this.contentMounted=!1,this.focusedSurface=null,this.refreshHostedTabs=()=>this.requestUpdate(),this.trackFocus=e=>{let t=e.composedPath().find(e=>e instanceof Element&&e.matches(`[data-region], [data-region-header]`));this.focusedSurface=t&&t.closest(`.sidebar-region`)===this.parentElement?t:null},this.closeFocusedPanel=e=>{if(e.defaultPrevented||!this.layout.open||this.layout.expanded&&!this.layout.expandedSide||!this.callbacks)return;let t=e instanceof CustomEvent?e.detail?.browserScope:void 0,n=typeof t==`string`?[...this.parentElement?.querySelectorAll(`[data-native-browser-scope]`)??[]].find(e=>e.dataset.nativeBrowserScope===t):void 0,r=document.activeElement instanceof HTMLIFrameElement?document.activeElement.closest(`[data-region]`):null,i=typeof t==`string`?n?.closest(`[data-region]`):r??this.focusedSurface,a=u(this.layout);if(!a||!i?.isConnected||i.closest(`.sidebar-region`)!==this.parentElement||!i.matches(`[data-region="side"], [data-region-header="side"]`)||i.closest(`[hidden], [inert], [aria-hidden="true"]`)||document.openClawModalLayers?.size||document.querySelector(`dialog[open], [aria-modal='true']`))return;e.preventDefault();let o=this.parentElement?.querySelector(`[data-region-header="side"]`)??null;this.focusedSurface=o;let s=()=>{this.layout.open&&this.focusedSurface===o&&o?.isConnected&&o.querySelector(`wa-tab[active]`)?.focus()},c=this.hostedTabsElement(a),l=c?.activeHostedTabId;if(c&&l&&c.hostedTabs.some(e=>e.id===l)){c.closeHostedTab(l).then(()=>this.updateComplete).then(s);return}this.callbacks.closeSlot(a.slot),this.requestUpdate(),this.updateComplete.then(s)}}connectedCallback(){super.connectedCallback(),this.nativeCloseListeners=new AbortController;let e={capture:!0,signal:this.nativeCloseListeners.signal};this.parentElement?.addEventListener(L,this.refreshHostedTabs,{signal:this.nativeCloseListeners.signal}),document.addEventListener(`pointerdown`,this.trackFocus,e),document.addEventListener(`focusin`,this.trackFocus,e),window.addEventListener(`openclaw:native-close-focused-panel`,this.closeFocusedPanel,e),this.requestUpdate()}disconnectedCallback(){this.nativeCloseListeners?.abort(),this.nativeCloseListeners=void 0,this.focusedSurface=null,this.geometryFrame!==null&&(cancelAnimationFrame(this.geometryFrame),this.geometryFrame=null),super.disconnectedCallback()}hostedTabsElement(e){return R(this.parentElement?.querySelector(`[data-panel-slot="${e.slot}"]`)?.firstElementChild)}deliverPanelEvent(e,t){let n=this.parentElement?.querySelector(`[data-panel-slot="${e}"]`)?.firstElementChild;return!(n instanceof HTMLElement)||typeof n.handleToggleRequest!=`function`?!1:(n.handleToggleRequest(t),!0)}panelTypes(){return this.availableSlots.map(e=>Y(this.panelDefinitions,e))}renderTypeMenu(){let e=new Set((this.layout.columns[0]?.panels??[]).map(e=>e.slot));return y`
<wa-dropdown
class="side-panel-type-menu"
placement="bottom-start"
-select=${t=>{let n=t.detail.item.value;if(n){this.callbacks?.openSlot(n);let t=Z.find(([e])=>e===n);t&&e.has(n)&&this.deliverPanelEvent(n,new CustomEvent(t[1],{detail:{...t[2]}}))}}}
>
<button
slot="trigger"
class="rail-header__action side-panel-type-menu__trigger"
type="button"
aria-label=${o(`chat.sidePanel.addTab`)}
title=${o(`chat.sidePanel.addTab`)}
>
${h.plus}
</button>
${this.panelTypes().filter(t=>Z.some(([e])=>e===t.slot)||!e.has(t.slot)).map(e=>y`
<wa-dropdown-item
class="side-panel-type-menu__item session-menu__item"
.value=${e.slot}
>
${X(e,!0)}
</wa-dropdown-item>
`)}
</wa-dropdown>
`}renderHostedTabIcon(e){if(e.favicon)return y`<img class="tabstrip-tab__favicon" src=${e.favicon} alt="" />`;let t=``;try{t=e.url?new URL(e.url).hostname:``}catch{}let n=t&&this.fetchFavicon?M(t,this.fetchFavicon,this.refreshHostedTabs):null;return n?y`<img class="tabstrip-tab__favicon" src=${n} alt="" />`:e.icon}renderHeader(e){let t=r(this.layout),n=t.flatMap(e=>{let t=this.hostedTabsElement(e);return t?[{panel:e,element:t,tabs:t.hostedTabs}]:[]}),i=e=>{for(let t of n){let n=`hosted:${t.panel.id}:`;if(e.startsWith(n)){let r=e.slice(n.length);if(t.tabs.some(e=>e.id===r))return{...t,tabId:r}}}return null},a=t.flatMap(t=>{let r=`${this.panelIdPrefix}-${encodeURIComponent(t.slot)}`,i=n.find(e=>e.panel.id===t.id);if(i?.tabs.length)return i.tabs.map(e=>({id:`hosted:${t.id}:${e.id}`,domId:`${this.panelIdPrefix}-tab-${encodeURIComponent(JSON.stringify([t.id,e.id]))}`,contentId:r,label:e.label,labelTooltip:e.label,title:e.title,icon:this.renderHostedTabIcon(e),statusLabel:e.statusLabel,badge:e.badge,className:e.className,closeLabel:`${o(`browser.closeTab`)}: ${e.label}`,group:t.id,draggable:!1,reorderId:t.id}));let a=Y(this.panelDefinitions,t.slot),s=t.slot===`conversation`&&this.conversationTab?.label?this.conversationTab:a;return[{id:t.id,domId:`${this.panelIdPrefix}-tab-${encodeURIComponent(t.id)}`,contentId:r,label:s.label,labelTooltip:t.slot===`dashboard`?o(this.layout.expanded&&this.layout.expandedSide&&e.activePanelId===t.id?`chat.sidePanel.restore`:`chat.sidePanel.expandPanel`,{panel:a.label}):s.label,onActivate:t.slot===`dashboard`?()=>this.callbacks?.togglePanelExpanded(t.id):void 0,icon:s.icon,closeLabel:o(`chat.sidebarColumns.close`,{panel:a.label})}]}),s=u(this.layout),c=n.find(e=>e.panel.id===s?.id),l=c?.tabs.some(e=>e.id===c.element.activeHostedTabId)?`hosted:${c.panel.id}:${c.element.activeHostedTabId}`:s?.id??null,d=e.panels.find(e=>e.id===s?.id),f=(d?this.panelActions[d.slot]:null)??null;return y`
<header
class="rail-header side-panel__header"
data-region-header="side"
=${v}
>
<div class="side-panel__header-tabs">
${z({tabs:a,activeId:l,ariaControls:e=>e.contentId,onSelect:t=>{let n=i(t);n?(e.activePanelId!==n.panel.id&&this.callbacks?.activatePanel(n.panel.id),n.element.selectHostedTab(n.tabId)):this.callbacks?.activatePanel(t)},onClose:async t=>{let n=i(t);if(n){await n.element.closeHostedTab(n.tabId);return}let r=e.panels.find(e=>e.id===t);r&&this.callbacks?.closeSlot(r.slot)},onNew:()=>void 0,newLabel:o(`chat.sidePanel.addTab`),newControl:S,separateTabs:!0,onReorder:(e,t,n)=>this.callbacks?.reorderPanel(e,t,n)})}
${this.renderTypeMenu()}
</div>
${this.renderHeaderActions(f,c?.element.hostedActions??S)}
</header>
`}renderHeaderActions(e,t){let n=u(this.layout),r=this.layout.expanded===!0&&this.layout.expandedSide===!0,i=r?o(`chat.sidePanel.restore`):o(`chat.sidePanel.expandPanel`,{panel:n?Y(this.panelDefinitions,n.slot).label:``});return y`<div class="rail-header__actions side-panel__actions">
${e||t!==S?y`<span class="side-panel__action-group side-panel__action-group--content">
${t} ${e}
</span>`:S}
<span class="side-panel__action-group side-panel__action-group--close">
${n?y`<openclaw-tooltip .content=${i}>
<button
class="rail-header__action side-panel__expand"
type="button"
aria-label=${i}
aria-pressed=${String(r)}
=${()=>this.callbacks?.togglePanelExpanded(n.id)}
>
${r?h.minimize:h.maximize}
</button>
</openclaw-tooltip>`:S}
<openclaw-tooltip .content=${o(`common.close`)}>
<button
class="rail-header__action side-panel__minimize"
type="button"
aria-label=${o(`common.close`)}
=${()=>this.callbacks?.setOpen(!1)}
>
${h.x}
</button>
</openclaw-tooltip>
</span>
</div>`}renderEmpty(e){if(e){let t=Y(this.panelDefinitions,e.slot);return y`<div class="side-panel-empty side-panel-empty--type">
${V({icon:t.icon,heading:t.label,description:t.empty.description,action:t.empty.action})}
</div>`}return y`<div class="side-panel-empty side-panel-empty--selector">
<div class="side-panel-empty__types">
${this.panelTypes().map(e=>y`<button
class="side-panel-empty__type"
type="button"
=${()=>this.callbacks?.openSlot(e.slot)}
>
${X(e)}
</button>`)}
</div>
</div>`}renderBody(e){return y`<div class="side-panel__body">
${T(this.panelDefinitions.flatMap(t=>(e?.panels??[]).filter(e=>e.slot===t.slot&&e.slot!==`conversation`)),e=>e.id,e=>y`<div
id=${`${this.panelIdPrefix}-${encodeURIComponent(e.slot)}`}
class="side-panel__panel"
role="region"
aria-label=${Y(this.panelDefinitions,e.slot).label}
data-panel-slot=${e.slot}
data-region=${e.id===this.layout.mainPanelId?`main`:`side`}
?hidden=${!i(this.layout,e.slot)}
>
${this.panelTemplates[e.slot]??this.renderEmpty(e)}
</div>`)}
${r(this.layout).length===0?y`<div class="side-panel__empty-body" data-region="side">${this.renderEmpty()}</div>`:S}
</div>`}renderDivider(e){let t=n(this.layout),r=()=>{let n=this.parentElement,r=n?.querySelector(`[data-region="main"]`),i=n?.querySelector(`[data-region="side"]:not([hidden])`),a=t===`bottom`?r?.getBoundingClientRect().height??0:r?.getBoundingClientRect().width??0,o=t===`bottom`?i?.getBoundingClientRect().height??e.height:i?.getBoundingClientRect().width??e.width;return{primarySize:a,panelSize:o,panelBeforeMain:t!==`bottom`&&t===`left`!=(getComputedStyle(n??this).direction===`rtl`),total:a+o}};return q({className:`sidebar-column__divider`,label:o(`chat.sidePanel.resize`),orientation:t===`bottom`?`horizontal`:`vertical`,splitRatio:.5,minRatio:.05,maxRatio:.95,measureRatio:()=>{let{primarySize:e,panelSize:t,panelBeforeMain:n,total:i}=r();return i>0?(n?t:e)/i:.5},measureSize:()=>r().total,onResize:n=>{let i=this.parentElement?.getBoundingClientRect(),a=t===`bottom`?i?.height??0:this.availableWidth>0?this.availableWidth:i?.width??0,o=r(),s=(o.total||a)*(o.panelBeforeMain?n.detail.splitRatio:1-n.detail.splitRatio),c=t===`bottom`?220:260,l=Math.max(c,a*.6);this.callbacks?.resizePanel(e.id,Math.max(c,Math.min(s,l)))}})}renderPanel(){let e=this.layout.columns[0];return e?(this.contentMounted||=this.layout.open===!0&&(!this.layout.expanded||this.layout.expandedSide===!0)||(a(this.layout)?.slot??`conversation`)!==`conversation`,y`${!this.narrow&&this.layout.open&&!this.layout.expanded?this.renderDivider(e):S}
<div class="side-panel">
${r(this.layout).length>0?this.renderHeader(e):S}
${this.contentMounted?this.renderBody(e):S}
</div>`):(this.contentMounted=!1,S)}updated(){let e=this.parentElement?.querySelector(`.sidebar-region__right-runtime`);e&&(w(this.renderPanel(),e),this.scheduleGeometryCommit())}scheduleGeometryCommit(){this.geometryFrame===null&&(this.geometryFrame=requestAnimationFrame(()=>{this.geometryFrame=null;let e=this.parentElement;if(!this.isConnected||!e)return;let t=e.querySelector(`.sidebar-region__right-runtime > .side-panel`),n=Array.from(e.querySelectorAll(`.sidebar-region__primary, .side-panel__panel`),e=>`${e.dataset.panelSlot??`conversation`}:${e.getBoundingClientRect().width}`).join(`:`);t?.dispatchEvent(new CustomEvent(F,{bubbles:!0,detail:{widthChanged:n!==this.previousGeometry}})),this.previousGeometry=n}))}render(){return S}},t([O({attribute:!1})],Q.prototype,`panelIdPrefix`,void 0),t([O({attribute:!1})],Q.prototype,`conversationTab`,void 0),t([O({attribute:!1})],Q.prototype,`layout`,void 0),t([O({attribute:!1})],Q.prototype,`panelDefinitions`,void 0),t([O({attribute:!1})],Q.prototype,`panelTemplates`,void 0),t([O({attribute:!1})],Q.prototype,`panelActions`,void 0),t([O({attribute:!1})],Q.prototype,`availableSlots`,void 0),t([O({attribute:!1})],Q.prototype,`fetchFavicon`,void 0),t([O({attribute:!1})],Q.prototype,`callbacks`,void 0),t([O({type:Boolean})],Q.prototype,`narrow`,void 0),t([O({type:Number})],Q.prototype,`availableWidth`,void 0),customElements.get(`openclaw-chat-sidebar-region`)||customElements.define(`openclaw-chat-sidebar-region`,Q)})))()}$();