tide-commander 1.96.0 → 1.97.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{BossLogsModal-BFy6Rxdn.js → BossLogsModal-CT25hD17.js} +1 -1
- package/dist/assets/{BossSpawnModal-KQyJYj_B.js → BossSpawnModal-9rS7AFkZ.js} +1 -1
- package/dist/assets/{ControlsModal-W_ghuG_Q.js → ControlsModal-D-mymoM7.js} +1 -1
- package/dist/assets/{DockerLogsModal-valTcuRy.js → DockerLogsModal-Ae-ZCeeP.js} +1 -1
- package/dist/assets/EmbeddedEditor-DLOOpM0K.js +33 -0
- package/dist/assets/{GmailOAuthSetup-AcW1zAlk.js → GmailOAuthSetup-C9NLhWLo.js} +1 -1
- package/dist/assets/{GoogleOAuthSetup-C9uZ46Oe.js → GoogleOAuthSetup-1kzgrPV6.js} +1 -1
- package/dist/assets/{IframeModal-CmWv7GXl.js → IframeModal-DKS0IFsr.js} +1 -1
- package/dist/assets/{IntegrationsPanel-CNvzosgx.js → IntegrationsPanel-CBvKOeud.js} +2 -2
- package/dist/assets/{LogViewerModal-imTE-619.js → LogViewerModal-Dlt8JfVg.js} +1 -1
- package/dist/assets/{MonitoringModal-DLxBY738.js → MonitoringModal-BM1IEZv6.js} +1 -1
- package/dist/assets/{PM2LogsModal-S4n0D11V.js → PM2LogsModal-B1-HUHWZ.js} +1 -1
- package/dist/assets/{RestoreArchivedAreaModal-B32sqCxN.js → RestoreArchivedAreaModal-DXmYo7fp.js} +1 -1
- package/dist/assets/{Scene2DCanvas-bEu0UPUm.js → Scene2DCanvas-CuUxSaPb.js} +1 -1
- package/dist/assets/{SceneManager-Ce3X0awy.js → SceneManager-UD3IHY20.js} +1 -1
- package/dist/assets/{SkillsPanel-Dj22nDU8.js → SkillsPanel-DjRBVrO2.js} +1 -1
- package/dist/assets/SlackMultiInstanceSetup-Csp81Dqn.js +2 -0
- package/dist/assets/{SpawnModal-F9nspdWd.js → SpawnModal-dg0mH3d9.js} +1 -1
- package/dist/assets/{SubordinateAssignmentModal-DT31CkPr.js → SubordinateAssignmentModal-CeBPRNNX.js} +1 -1
- package/dist/assets/{TriggerManagerPanel-CVJ9ozHz.js → TriggerManagerPanel-D1QPpFhP.js} +1 -1
- package/dist/assets/{WorkflowEditorPanel-BYRi0cU9.js → WorkflowEditorPanel-IIsptZgp.js} +1 -1
- package/dist/assets/{index-ByfAbkqv.js → index-BGh9tRSy.js} +1 -1
- package/dist/assets/{index-DkjWoHhy.js → index-CIqkVLo1.js} +1 -1
- package/dist/assets/{index-B9G4hrFR.js → index-CNDUxsGy.js} +1 -1
- package/dist/assets/{index-C5wC_Xis.js → index-CR9w26tq.js} +1 -1
- package/dist/assets/{index-BmjrPptb.js → index-CsyPNc8u.js} +1 -1
- package/dist/assets/{index-DqZhHROd.js → index-DEI-vrXk.js} +1 -1
- package/dist/assets/{index-CLr8DpLX.js → index-h-IcmGfB.js} +2 -2
- package/dist/assets/index-sDgBtEgH.js +19 -0
- package/dist/assets/{index-DJm7oMXk.js → index-vJkimYqD.js} +1 -1
- package/dist/assets/main-BV_IuaBg.css +1 -0
- package/dist/assets/main-klWBzHh0.js +214 -0
- package/dist/assets/{web-D-a3phls.js → web-BgPjNMBK.js} +1 -1
- package/dist/assets/{web-CLuvtqCm.js → web-BmPSJLwQ.js} +1 -1
- package/dist/assets/{web-DM2bFWBN.js → web-Dggt4D4N.js} +1 -1
- package/dist/index.html +2 -2
- package/dist/src/packages/server/integrations/slack/slack-config.js +13 -0
- package/dist/src/packages/server/integrations/slack/slack-trigger-handler.js +12 -4
- package/package.json +1 -1
- package/dist/assets/EmbeddedEditor-CIsFWo6A.js +0 -1
- package/dist/assets/SlackMultiInstanceSetup-J9NdRY0U.js +0 -2
- package/dist/assets/index-BPy8NE5B.js +0 -51
- package/dist/assets/main-9uTEp9Lr.js +0 -214
- package/dist/assets/main-BfT_95fk.css +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{ck as t}from"./main-
|
|
1
|
+
import{ck as t}from"./main-klWBzHh0.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";class o extends t{constructor(){super(),this.handleVisibilityChange=()=>{const e={isActive:document.hidden!==!0};this.notifyListeners("appStateChange",e),document.hidden?this.notifyListeners("pause",null):this.notifyListeners("resume",null)},document.addEventListener("visibilitychange",this.handleVisibilityChange,!1)}exitApp(){throw this.unimplemented("Not implemented on web.")}async getInfo(){throw this.unimplemented("Not implemented on web.")}async getLaunchUrl(){return{url:""}}async getState(){return{isActive:document.hidden!==!0}}async minimizeApp(){throw this.unimplemented("Not implemented on web.")}async toggleBackButtonHandler(){throw this.unimplemented("Not implemented on web.")}async getAppLanguage(){return{value:navigator.language.split("-")[0].toLowerCase()}}}export{o as AppWeb};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{ck as a}from"./main-
|
|
1
|
+
import{ck as a}from"./main-klWBzHh0.js";import{ImpactStyle as i,NotificationType as r}from"./index-h-IcmGfB.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";class h extends a{constructor(){super(...arguments),this.selectionStarted=!1}async impact(t){const e=this.patternForImpact(t==null?void 0:t.style);this.vibrateWithPattern(e)}async notification(t){const e=this.patternForNotification(t==null?void 0:t.type);this.vibrateWithPattern(e)}async vibrate(t){const e=(t==null?void 0:t.duration)||300;this.vibrateWithPattern([e])}async selectionStart(){this.selectionStarted=!0}async selectionChanged(){this.selectionStarted&&this.vibrateWithPattern([70])}async selectionEnd(){this.selectionStarted=!1}patternForImpact(t=i.Heavy){return t===i.Medium?[43]:t===i.Light?[20]:[61]}patternForNotification(t=r.Success){return t===r.Warning?[30,40,30,50,60]:t===r.Error?[27,45,50]:[35,65,21]}vibrateWithPattern(t){if(navigator.vibrate)navigator.vibrate(t);else throw this.unavailable("Browser does not support the vibrate API")}}export{h as HapticsWeb};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{ck as s}from"./main-
|
|
1
|
+
import{ck as s}from"./main-klWBzHh0.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";class l extends s{constructor(){super(...arguments),this.pending=[],this.deliveredNotifications=[],this.hasNotificationSupport=()=>{if(!("Notification"in window)||!Notification.requestPermission)return!1;if(Notification.permission!=="granted")try{new Notification("")}catch(i){if(i instanceof Error&&i.name==="TypeError")return!1}return!0}}async getDeliveredNotifications(){const i=[];for(const t of this.deliveredNotifications){const e={title:t.title,id:parseInt(t.tag),body:t.body};i.push(e)}return{notifications:i}}async removeDeliveredNotifications(i){for(const t of i.notifications){const e=this.deliveredNotifications.find(n=>n.tag===String(t.id));e==null||e.close(),this.deliveredNotifications=this.deliveredNotifications.filter(()=>!e)}}async removeAllDeliveredNotifications(){for(const i of this.deliveredNotifications)i.close();this.deliveredNotifications=[]}async createChannel(){throw this.unimplemented("Not implemented on web.")}async deleteChannel(){throw this.unimplemented("Not implemented on web.")}async listChannels(){throw this.unimplemented("Not implemented on web.")}async schedule(i){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");for(const t of i.notifications)this.sendNotification(t);return{notifications:i.notifications.map(t=>({id:t.id}))}}async getPending(){return{notifications:this.pending}}async registerActionTypes(){throw this.unimplemented("Not implemented on web.")}async cancel(i){this.pending=this.pending.filter(t=>!i.notifications.find(e=>e.id===t.id))}async areEnabled(){const{display:i}=await this.checkPermissions();return{value:i==="granted"}}async changeExactNotificationSetting(){throw this.unimplemented("Not implemented on web.")}async checkExactNotificationSetting(){throw this.unimplemented("Not implemented on web.")}async requestPermissions(){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");return{display:this.transformNotificationPermission(await Notification.requestPermission())}}async checkPermissions(){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");return{display:this.transformNotificationPermission(Notification.permission)}}transformNotificationPermission(i){switch(i){case"granted":return"granted";case"denied":return"denied";default:return"prompt"}}sendPending(){var i;const t=[],e=new Date().getTime();for(const n of this.pending)!((i=n.schedule)===null||i===void 0)&&i.at&&n.schedule.at.getTime()<=e&&(this.buildNotification(n),t.push(n));this.pending=this.pending.filter(n=>!t.find(o=>o===n))}sendNotification(i){var t;if(!((t=i.schedule)===null||t===void 0)&&t.at){const e=i.schedule.at.getTime()-new Date().getTime();this.pending.push(i),setTimeout(()=>{this.sendPending()},e);return}this.buildNotification(i)}buildNotification(i){const t=new Notification(i.title,{body:i.body,tag:String(i.id)});return t.addEventListener("click",this.onClick.bind(this,i),!1),t.addEventListener("show",this.onShow.bind(this,i),!1),t.addEventListener("close",()=>{this.deliveredNotifications=this.deliveredNotifications.filter(()=>!this)},!1),this.deliveredNotifications.push(t),t}onClick(i){const t={actionId:"tap",notification:i};this.notifyListeners("localNotificationActionPerformed",t)}onShow(i){this.notifyListeners("localNotificationReceived",i)}}export{l as LocalNotificationsWeb};
|
package/dist/index.html
CHANGED
|
@@ -22,10 +22,10 @@
|
|
|
22
22
|
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16x16.png" />
|
|
23
23
|
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png" />
|
|
24
24
|
<title>Tide Commander</title>
|
|
25
|
-
<script type="module" crossorigin src="/assets/main-
|
|
25
|
+
<script type="module" crossorigin src="/assets/main-klWBzHh0.js"></script>
|
|
26
26
|
<link rel="modulepreload" crossorigin href="/assets/vendor-react--Eh9ivFN.js">
|
|
27
27
|
<link rel="modulepreload" crossorigin href="/assets/vendor-three-Chj50gSY.js">
|
|
28
|
-
<link rel="stylesheet" crossorigin href="/assets/main-
|
|
28
|
+
<link rel="stylesheet" crossorigin href="/assets/main-BV_IuaBg.css">
|
|
29
29
|
</head>
|
|
30
30
|
<body>
|
|
31
31
|
<div id="app"></div>
|
|
@@ -19,6 +19,7 @@ const DEFAULT_CONFIG = {
|
|
|
19
19
|
pollingMinMsBetweenCalls: 1500,
|
|
20
20
|
pollingUseSearch: false,
|
|
21
21
|
mirrorOwnMessages: false,
|
|
22
|
+
reactOnTrigger: true,
|
|
22
23
|
currentMode: 'none',
|
|
23
24
|
};
|
|
24
25
|
// ─── Config File Persistence ───
|
|
@@ -201,6 +202,14 @@ export const slackConfigSchema = [
|
|
|
201
202
|
defaultValue: false,
|
|
202
203
|
group: 'General',
|
|
203
204
|
},
|
|
205
|
+
{
|
|
206
|
+
key: 'reactOnTrigger',
|
|
207
|
+
label: 'Auto-react with :eyes: on trigger',
|
|
208
|
+
type: 'boolean',
|
|
209
|
+
description: 'When a Slack trigger fires on an incoming message, react with 👀 as a visual acknowledgement. Default on. Per-instance — turn off for accounts where the reaction is noisy.',
|
|
210
|
+
defaultValue: true,
|
|
211
|
+
group: 'General',
|
|
212
|
+
},
|
|
204
213
|
];
|
|
205
214
|
// ─── Per-Instance Secret Keys ───
|
|
206
215
|
/**
|
|
@@ -243,6 +252,7 @@ export function getConfigValues(secrets, instanceId = DEFAULT_INSTANCE_ID) {
|
|
|
243
252
|
pollingMinMsBetweenCalls: config.pollingMinMsBetweenCalls ?? 1500,
|
|
244
253
|
pollingUseSearch: config.pollingUseSearch ?? false,
|
|
245
254
|
mirrorOwnMessages: config.mirrorOwnMessages ?? false,
|
|
255
|
+
reactOnTrigger: config.reactOnTrigger ?? true,
|
|
246
256
|
currentMode: config.currentMode ?? 'none',
|
|
247
257
|
// Mask secret values for UI display
|
|
248
258
|
SLACK_BOT_TOKEN: secrets.get(instanceSecretKey('SLACK_BOT_TOKEN', instanceId)) ? '********' : '',
|
|
@@ -296,6 +306,9 @@ export async function setConfigValues(values, secrets, instanceId = DEFAULT_INST
|
|
|
296
306
|
if (typeof values.mirrorOwnMessages === 'boolean') {
|
|
297
307
|
updates.mirrorOwnMessages = values.mirrorOwnMessages;
|
|
298
308
|
}
|
|
309
|
+
if (typeof values.reactOnTrigger === 'boolean') {
|
|
310
|
+
updates.reactOnTrigger = values.reactOnTrigger;
|
|
311
|
+
}
|
|
299
312
|
updateConfig(updates, instanceId);
|
|
300
313
|
}
|
|
301
314
|
// ─── Mode Detection ───
|
|
@@ -10,10 +10,15 @@
|
|
|
10
10
|
import * as slackClient from './slack-client.js';
|
|
11
11
|
import { listInstances } from './slack-instance.js';
|
|
12
12
|
import { listInstanceMetas } from './slack-instance-manifest.js';
|
|
13
|
+
import { loadConfig } from './slack-config.js';
|
|
13
14
|
import { formatAttachmentLine } from '../../services/attachment-downloader.js';
|
|
14
15
|
const unsubscribers = [];
|
|
15
|
-
/**
|
|
16
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Global kill-switch: `SLACK_REACT_ON_TRIGGER=false` (or 0/no/off) disables the
|
|
18
|
+
* auto-:eyes: ack across every instance regardless of per-instance config.
|
|
19
|
+
* Defaults to enabled when unset.
|
|
20
|
+
*/
|
|
21
|
+
function envAllowsReact() {
|
|
17
22
|
const raw = (process.env.SLACK_REACT_ON_TRIGGER ?? '').toLowerCase().trim();
|
|
18
23
|
if (!raw)
|
|
19
24
|
return true;
|
|
@@ -22,7 +27,7 @@ function reactOnTriggerEnabled() {
|
|
|
22
27
|
export const slackTriggerHandler = {
|
|
23
28
|
triggerType: 'slack',
|
|
24
29
|
async startListening(onEvent) {
|
|
25
|
-
const
|
|
30
|
+
const envOn = envAllowsReact();
|
|
26
31
|
// Subscribe to every instance the manifest knows about. Unknown instances
|
|
27
32
|
// (created later via the UI) are auto-created with `getInstance()` when
|
|
28
33
|
// reconnect runs, but we re-subscribe on each integration shutdown/init
|
|
@@ -32,7 +37,10 @@ export const slackTriggerHandler = {
|
|
|
32
37
|
const allInstances = listInstances().filter((i) => idSet.has(i.id));
|
|
33
38
|
for (const inst of allInstances) {
|
|
34
39
|
const off = inst.onMessage((message) => {
|
|
35
|
-
|
|
40
|
+
// Per-instance toggle is read fresh on each message so flipping the
|
|
41
|
+
// checkbox in the UI takes effect without restarting the trigger.
|
|
42
|
+
const perInstance = loadConfig(inst.id).reactOnTrigger ?? true;
|
|
43
|
+
if (envOn && perInstance) {
|
|
36
44
|
// Use the instance-specific reaction so it posts as the right account.
|
|
37
45
|
inst.addReaction({ channel: message.channel, ts: message.ts, name: 'eyes' })
|
|
38
46
|
.catch(() => { });
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as e,j as s}from"./main-9uTEp9Lr.js";import{g as j,o as k,E as f,l as N,h as R,a as T,f as A,d as w,r as C,i as K,b as L,c as M,e as q,j as B,s as D,k as G,m as H,n as O,p as V,q as W,t as F,u as I,v as U,w as Y,x as z}from"./index-BPy8NE5B.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";const J=1e3,$=({content:_,extension:p,onSave:h,onCancel:b})=>{const c=e.useRef(null),d=e.useRef(null),t=e.useRef(null),o=e.useRef(!1),v=e.useRef(h);v.current=h;const[u,i]=e.useState("idle"),[S,l]=e.useState(null),a=e.useCallback(async()=>{if(!(!d.current||o.current)){o.current=!0,i("saving"),l(null);try{const r=d.current.state.doc.toString();await v.current(r),i("saved"),setTimeout(()=>i(n=>n==="saved"?"idle":n),1500)}catch(r){i("error"),l(r.message||"Save failed")}finally{o.current=!1}}},[]),x=e.useCallback(()=>{t.current&&clearTimeout(t.current),t.current=setTimeout(()=>{a()},J)},[a]),g=e.useCallback(()=>{t.current&&(clearTimeout(t.current),t.current=null,a()),b()},[b,a]);return e.useEffect(()=>()=>{t.current&&clearTimeout(t.current)},[]),e.useEffect(()=>{if(!c.current)return;const r=j(p),n=[N(),R(),T(),A(),w(),C(),K(),L(),M(),q(),B(),D({top:!0}),G(z,{fallback:!0}),k,f.lineWrapping,H.of([...O,...V,...W,...F,...I,U,{key:"Mod-s",run:()=>(t.current&&(clearTimeout(t.current),t.current=null),a(),!0)},{key:"Escape",run:()=>(g(),!0)}]),f.updateListener.of(y=>{y.docChanged&&(l(null),x())})];r&&n.push(r);const E=Y.create({doc:_,extensions:n}),m=new f({state:E,parent:c.current});return d.current=m,requestAnimationFrame(()=>m.focus()),()=>{m.destroy(),d.current=null}},[]),s.jsxs("div",{className:"embedded-editor",children:[s.jsxs("div",{className:"embedded-editor__toolbar",children:[s.jsxs("div",{className:"embedded-editor__toolbar-left",children:[u==="saving"&&s.jsx("span",{className:"embedded-editor__status embedded-editor__status--saving",children:"Saving..."}),u==="saved"&&s.jsx("span",{className:"embedded-editor__status embedded-editor__status--saved",children:"Saved"}),u==="error"&&s.jsx("span",{className:"embedded-editor__status embedded-editor__status--error",children:S||"Save failed"})]}),s.jsxs("div",{className:"embedded-editor__toolbar-right",children:[s.jsx("span",{className:"embedded-editor__shortcut-hint",children:"Auto-saves · Esc to close"}),s.jsx("button",{className:"embedded-editor__btn embedded-editor__btn--close",onClick:g,children:"Close"})]})]}),s.jsx("div",{className:"embedded-editor__container",ref:c})]})};export{$ as EmbeddedEditor};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{r as u,j as e,aJ as b,l as m}from"./main-9uTEp9Lr.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";const C=["public_channel","private_channel","im","mpim"],O={public_channel:"Public channels",private_channel:"Private channels",im:"1:1 DMs",mpim:"Group DMs"};function M(l){const i=new Set;for(const s of(l||"").split(",")){const f=s.trim();C.includes(f)&&i.add(f)}return i}function N(l){return C.filter(i=>l.has(i)).join(",")}const t={container:{display:"flex",gap:16,minHeight:420},list:{width:200,flexShrink:0,background:"var(--surface-1, #181825)",borderRadius:8,border:"1px solid var(--border, #313244)",padding:8,display:"flex",flexDirection:"column",gap:4},listItem:l=>({padding:"8px 10px",borderRadius:6,cursor:"pointer",background:l?"rgba(137,180,250,0.15)":"transparent",border:l?"1px solid rgba(137,180,250,0.3)":"1px solid transparent",color:l?"#cdd6f4":"#a6adc8",fontSize:13}),label:{fontWeight:500},sub:{fontSize:11,color:"#6c7086",marginTop:2},addBtn:{marginTop:8,padding:"8px 10px",borderRadius:6,background:"transparent",color:"#89b4fa",border:"1px dashed rgba(137,180,250,0.4)",cursor:"pointer",fontSize:13},editor:{flex:1,display:"flex",flexDirection:"column",gap:12},field:{display:"flex",flexDirection:"column",gap:4},fieldLabel:{fontSize:12,fontWeight:500,color:"#a6adc8"},fieldDesc:{fontSize:11,color:"#6c7086"},input:{padding:"8px 10px",background:"var(--surface-0, #1e1e2e)",border:"1px solid var(--border, #313244)",borderRadius:6,color:"#cdd6f4",fontSize:13,fontFamily:"inherit"},badge:l=>{const s={socket:"#a6e3a1",polling:"#89b4fa",none:"#6c7086"}[l]??"#6c7086";return{display:"inline-block",padding:"2px 8px",borderRadius:4,fontSize:11,fontWeight:500,background:`${s}26`,color:s,border:`1px solid ${s}55`}},rowGap:{display:"flex",gap:12},buttons:{display:"flex",gap:8,marginTop:12},btnPrimary:{padding:"8px 16px",background:"#89b4fa",color:"#1e1e2e",border:"none",borderRadius:6,cursor:"pointer",fontWeight:500,fontSize:13},btnSecondary:{padding:"8px 16px",background:"transparent",color:"#cdd6f4",border:"1px solid var(--border, #313244)",borderRadius:6,cursor:"pointer",fontSize:13},btnDanger:{padding:"8px 16px",background:"transparent",color:"#f38ba8",border:"1px solid rgba(243,139,168,0.4)",borderRadius:6,cursor:"pointer",fontSize:13},alert:l=>({padding:"8px 12px",borderRadius:6,fontSize:12,background:l==="error"?"rgba(243,139,168,0.15)":"rgba(166,227,161,0.15)",color:l==="error"?"#f38ba8":"#a6e3a1",border:`1px solid ${l==="error"?"rgba(243,139,168,0.3)":"rgba(166,227,161,0.3)"}`})},j="/api/slack/instances";async function R(){const l=await b(m(j));if(!l.ok)throw new Error(`HTTP ${l.status}`);return(await l.json()).instances}async function B(l){const i=await b(m(`${j}/${encodeURIComponent(l)}/values`));if(!i.ok)throw new Error(`HTTP ${i.status}`);return(await i.json()).values}async function K(l,i){const s=await b(m(j),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({id:l,label:i})});if(!s.ok){const f=await s.json().catch(()=>({}));throw new Error(f.error||`HTTP ${s.status}`)}}async function H(l,i){const s=await b(m(`${j}/${encodeURIComponent(l)}`),{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)});if(!s.ok){const f=await s.json().catch(()=>({}));throw new Error(f.error||`HTTP ${s.status}`)}}async function W(l){const i=await b(m(`${j}/${encodeURIComponent(l)}`),{method:"DELETE"});if(!i.ok){const s=await i.json().catch(()=>({}));throw new Error(s.error||`HTTP ${i.status}`)}}const V=({integration:l,onCancel:i})=>{const[s,f]=u.useState([]),[o,v]=u.useState("default"),[a,S]=u.useState(null),[T,P]=u.useState(null),[g,D]=u.useState(""),[I,A]=u.useState(!1),[L,E]=u.useState(!1),[w,x]=u.useState(null),y=u.useCallback(async()=>{try{const n=await R();f(n),!n.some(c=>c.id===o)&&n.length>0&&v(n[0].id)}catch(n){x({kind:"error",message:`Failed to load instances: ${n.message}`})}},[o]),k=u.useCallback(async()=>{if(o){A(!0);try{const n=await B(o);S(n),P(n);const r=s.find(c=>c.id===o);D((r==null?void 0:r.label)??o)}catch(n){x({kind:"error",message:`Failed to load instance: ${n.message}`})}finally{A(!1)}}},[o,s]);u.useEffect(()=>{y()},[y]),u.useEffect(()=>{k()},[k]);const _=async()=>{const n=window.prompt('Instance id (kebab-case, e.g. "personal", "team-bot"):');if(!n)return;const r=window.prompt("Display label:",n)||n;try{await K(n.trim(),r.trim()),await y(),v(n.trim()),x({kind:"success",message:`Created "${n}"`})}catch(c){x({kind:"error",message:c.message})}},z=async()=>{if(o!=="default"&&window.confirm(`Delete Slack instance "${o}"? This disconnects it and removes its config.`))try{await W(o),v("default"),await y(),x({kind:"success",message:"Instance deleted"})}catch(n){x({kind:"error",message:n.message})}},$=async()=>{if(!(!a||!T)){E(!0);try{const n={};Object.keys(a).forEach(p=>{const h=a[p];if(h!==T[p]){if((p==="SLACK_BOT_TOKEN"||p==="SLACK_APP_TOKEN")&&h==="********")return;n[p]=h}});const r=s.find(p=>p.id===o),c=r&&g.trim()&&g.trim()!==r.label;await H(o,{label:c?g.trim():void 0,values:Object.keys(n).length>0?n:void 0}),x({kind:"success",message:"Saved. Slack will reconnect with the new settings."}),await y(),await k()}catch(n){x({kind:"error",message:n.message})}finally{E(!1)}}},d=(n,r)=>{a&&S({...a,[n]:r})};return e.jsxs("div",{children:[e.jsx("div",{style:{marginBottom:12,fontSize:12,color:"#a6adc8"},children:"Add multiple Slack connections side-by-side. The default instance maps to your existing bot / token; add more for personal (xoxp-) tokens or additional workspaces."}),w&&e.jsx("div",{style:{...t.alert(w.kind),marginBottom:12},children:w.message}),e.jsxs("div",{style:t.container,children:[e.jsxs("div",{style:t.list,children:[s.map(n=>{var c,p,h;const r=((c=n.config)==null?void 0:c.currentMode)??"none";return e.jsxs("div",{style:t.listItem(n.id===o),onClick:()=>v(n.id),children:[e.jsx("div",{style:t.label,children:n.label}),e.jsxs("div",{style:t.sub,children:[e.jsx("span",{style:t.badge(r),children:r==="none"?"—":r}),(p=n.status)!=null&&p.connected?" • connected":(h=n.status)!=null&&h.error?" • error":" • idle"]})]},n.id)}),e.jsx("button",{type:"button",style:t.addBtn,onClick:_,children:"+ Add Instance"})]}),e.jsxs("div",{style:t.editor,children:[I&&e.jsx("div",{style:{color:"#6c7086",fontSize:13},children:"Loading…"}),!I&&a&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{style:t.field,children:[e.jsx("span",{style:t.fieldLabel,children:"Display label"}),e.jsx("input",{type:"text",style:t.input,value:g,onChange:n=>D(n.target.value),disabled:!1}),e.jsxs("span",{style:t.fieldDesc,children:["Shown in the instance list. Id is fixed: ",e.jsx("code",{children:o})]})]}),e.jsxs("div",{style:t.field,children:[e.jsxs("label",{style:{display:"flex",alignItems:"center",gap:8,cursor:"pointer"},children:[e.jsx("input",{type:"checkbox",checked:a.enabled,onChange:n=>d("enabled",n.target.checked)}),e.jsx("span",{style:t.fieldLabel,children:"Enabled"})]}),e.jsx("span",{style:t.fieldDesc,children:"Toggle off to disconnect this instance without deleting its config."})]}),e.jsxs("div",{style:t.field,children:[e.jsxs("label",{style:{display:"flex",alignItems:"center",gap:8,cursor:"pointer"},children:[e.jsx("input",{type:"checkbox",checked:a.mirrorOwnMessages,onChange:n=>d("mirrorOwnMessages",n.target.checked)}),e.jsx("span",{style:t.fieldLabel,children:"Mirror messages I send too"})]}),e.jsxs("span",{style:t.fieldDesc,children:["Capture your outgoing messages alongside incoming ones (logged as ",e.jsx("code",{children:"direction:outbound"}),"). Recommended for personal (xoxp-) tokens. Triggers do not fire on your own messages — that would loop."]})]}),e.jsxs("div",{style:t.field,children:[e.jsx("span",{style:t.fieldLabel,children:"Slack Token"}),e.jsx("input",{type:"password",style:t.input,placeholder:"xoxb-... or xoxp-...",value:a.SLACK_BOT_TOKEN,onChange:n=>d("SLACK_BOT_TOKEN",n.target.value)}),e.jsxs("span",{style:t.fieldDesc,children:["Bot token (xoxb-) → Socket Mode. User token (xoxp-) → Web API polling (~30-60s lag). Stored encrypted under a per-instance key; leave as ",e.jsx("code",{children:"********"})," to keep the existing token."]})]}),e.jsxs("div",{style:t.field,children:[e.jsx("span",{style:t.fieldLabel,children:"App Token (Socket Mode only)"}),e.jsx("input",{type:"password",style:t.input,placeholder:"xapp-...",value:a.SLACK_APP_TOKEN,onChange:n=>d("SLACK_APP_TOKEN",n.target.value)}),e.jsx("span",{style:t.fieldDesc,children:"Required for xoxb- only. Leave blank for xoxp- (polling mode)."})]}),e.jsxs("div",{style:t.rowGap,children:[e.jsxs("div",{style:{...t.field,flex:1},children:[e.jsx("span",{style:t.fieldLabel,children:"Inbound Mode"}),e.jsxs("select",{style:t.input,value:a.authMode,onChange:n=>d("authMode",n.target.value),children:[e.jsx("option",{value:"auto",children:"Auto (from token prefix)"}),e.jsx("option",{value:"socket",children:"Socket Mode (xoxb-)"}),e.jsx("option",{value:"polling",children:"Polling (xoxp-)"})]})]}),e.jsxs("div",{style:{...t.field,flex:1},children:[e.jsx("span",{style:t.fieldLabel,children:"Default Channel"}),e.jsx("input",{type:"text",style:t.input,placeholder:"C0123456789",value:a.defaultChannelId,onChange:n=>d("defaultChannelId",n.target.value)})]})]}),e.jsxs("div",{style:t.rowGap,children:[e.jsxs("div",{style:{...t.field,flex:1},children:[e.jsx("span",{style:t.fieldLabel,children:"Polling Interval (s)"}),e.jsx("input",{type:"number",style:t.input,min:10,max:600,value:a.pollingIntervalSec,onChange:n=>d("pollingIntervalSec",Number(n.target.value))})]}),e.jsxs("div",{style:{...t.field,flex:1},children:[e.jsx("span",{style:t.fieldLabel,children:"Concurrency"}),e.jsx("input",{type:"number",style:t.input,min:1,max:8,value:a.pollingConcurrency,onChange:n=>d("pollingConcurrency",Number(n.target.value))})]}),e.jsxs("div",{style:{...t.field,flex:1},children:[e.jsx("span",{style:t.fieldLabel,children:"Backfill Cap (msgs)"}),e.jsx("input",{type:"number",style:t.input,min:1,max:1e3,value:a.pollingBackfillMessageCap,onChange:n=>d("pollingBackfillMessageCap",Number(n.target.value))})]}),e.jsxs("div",{style:{...t.field,flex:1},children:[e.jsx("span",{style:t.fieldLabel,children:"Min ms between calls"}),e.jsx("input",{type:"number",style:t.input,min:0,max:1e4,value:a.pollingMinMsBetweenCalls,onChange:n=>d("pollingMinMsBetweenCalls",Number(n.target.value))}),e.jsx("span",{style:{...t.fieldDesc,fontSize:11},children:"Throttle. 1500 ≈ 40 req/min. Set 0 to disable."})]})]}),e.jsxs("div",{style:t.field,children:[e.jsx("span",{style:t.fieldLabel,children:"Channel Types (poll all of these)"}),e.jsx("div",{style:{display:"flex",flexWrap:"wrap",gap:12,marginTop:4},children:C.map(n=>{const c=M(a.pollingChannelTypes).has(n);return e.jsxs("label",{style:{display:"flex",alignItems:"center",gap:6,cursor:"pointer",fontSize:13},children:[e.jsx("input",{type:"checkbox",checked:c,onChange:p=>{const h=new Set(M(a.pollingChannelTypes));p.target.checked?h.add(n):h.delete(n),d("pollingChannelTypes",N(h))}}),e.jsx("span",{children:O[n]})]},n)})}),e.jsx("span",{style:t.fieldDesc,children:"Determines which channel types are polled when the allowlist below is empty. Tick all four for full coverage. Heads-up: hundreds of channels at once can hit Slack's rate limit (~50 req/min) — use the allowlist to narrow down."})]}),e.jsxs("div",{style:t.field,children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between"},children:[e.jsx("span",{style:t.fieldLabel,children:"Channel Allowlist (optional)"}),a.pollingChannelAllowlist&&e.jsx("button",{type:"button",style:{...t.btnSecondary,padding:"4px 10px",fontSize:12},onClick:()=>d("pollingChannelAllowlist",""),title:"Clear the allowlist — fall back to polling all channels per the type checkboxes above.",children:"Include all (clear list)"})]}),e.jsx("textarea",{style:{...t.input,minHeight:60,fontFamily:"monospace",fontSize:12},placeholder:`C0123456789, G0987654321
|
|
2
|
-
C9999999999`,value:a.pollingChannelAllowlist,onChange:n=>d("pollingChannelAllowlist",n.target.value)}),e.jsx("span",{style:t.fieldDesc,children:'Comma- or newline-separated channel IDs. When set, polling restricts to these channels (plus DMs if "Always include DMs" is on). The Channel Types checkboxes above are ignored while an allowlist is active. Leave blank to fall back to polling all channels per the type checkboxes.'})]}),e.jsxs("div",{style:t.field,children:[e.jsxs("label",{style:{display:"flex",alignItems:"center",gap:8,cursor:"pointer"},children:[e.jsx("input",{type:"checkbox",checked:a.pollingDmsAlways,onChange:n=>d("pollingDmsAlways",n.target.checked)}),e.jsx("span",{style:t.fieldLabel,children:"Always include DMs"})]}),e.jsx("span",{style:t.fieldDesc,children:"When the allowlist is set, still poll all 1:1 DMs (D-prefix). Default on. Turn off for strict allowlist-only mode."})]}),e.jsxs("div",{style:t.buttons,children:[e.jsx("button",{type:"button",style:t.btnPrimary,onClick:$,disabled:L,children:L?"Saving…":"Save & Reconnect"}),e.jsx("button",{type:"button",style:t.btnSecondary,onClick:i,children:"Close"}),o!=="default"&&e.jsx("button",{type:"button",style:{...t.btnDanger,marginLeft:"auto"},onClick:z,children:"Delete Instance"})]})]})]})]})]})};export{V as SlackMultiInstanceSetup,V as default};
|