botmux 2.107.0 → 2.108.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/README.en.md +17 -14
- package/README.md +19 -14
- package/dist/adapters/backend/sandbox.d.ts +3 -1
- package/dist/adapters/backend/sandbox.d.ts.map +1 -1
- package/dist/adapters/backend/sandbox.js +19 -3
- package/dist/adapters/backend/sandbox.js.map +1 -1
- package/dist/adapters/backend/tmux-backend.d.ts.map +1 -1
- package/dist/adapters/backend/tmux-backend.js +16 -1
- package/dist/adapters/backend/tmux-backend.js.map +1 -1
- package/dist/adapters/backend/tmux-pipe-backend.d.ts +24 -15
- package/dist/adapters/backend/tmux-pipe-backend.d.ts.map +1 -1
- package/dist/adapters/backend/tmux-pipe-backend.js +75 -43
- package/dist/adapters/backend/tmux-pipe-backend.js.map +1 -1
- package/dist/adapters/cli/genius.d.ts.map +1 -1
- package/dist/adapters/cli/genius.js +9 -15
- package/dist/adapters/cli/genius.js.map +1 -1
- package/dist/adapters/cli/grok.d.ts +73 -0
- package/dist/adapters/cli/grok.d.ts.map +1 -0
- package/dist/adapters/cli/grok.js +298 -0
- package/dist/adapters/cli/grok.js.map +1 -0
- package/dist/adapters/cli/oh-my-pi.d.ts.map +1 -1
- package/dist/adapters/cli/oh-my-pi.js +133 -12
- package/dist/adapters/cli/oh-my-pi.js.map +1 -1
- package/dist/adapters/cli/registry.d.ts +2 -1
- package/dist/adapters/cli/registry.d.ts.map +1 -1
- package/dist/adapters/cli/registry.js +3 -1
- package/dist/adapters/cli/registry.js.map +1 -1
- package/dist/adapters/cli/shared-hints.d.ts +8 -4
- package/dist/adapters/cli/shared-hints.d.ts.map +1 -1
- package/dist/adapters/cli/shared-hints.js +8 -4
- package/dist/adapters/cli/shared-hints.js.map +1 -1
- package/dist/adapters/cli/types.d.ts +18 -16
- package/dist/adapters/cli/types.d.ts.map +1 -1
- package/dist/adapters/hook-installer.d.ts +5 -4
- package/dist/adapters/hook-installer.d.ts.map +1 -1
- package/dist/adapters/hook-installer.js +42 -0
- package/dist/adapters/hook-installer.js.map +1 -1
- package/dist/cli/send-dispatch.d.ts +21 -0
- package/dist/cli/send-dispatch.d.ts.map +1 -1
- package/dist/cli/send-dispatch.js +159 -0
- package/dist/cli/send-dispatch.js.map +1 -1
- package/dist/cli/session-list-liveness.d.ts +22 -0
- package/dist/cli/session-list-liveness.d.ts.map +1 -0
- package/dist/cli/session-list-liveness.js +22 -0
- package/dist/cli/session-list-liveness.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +182 -33
- package/dist/cli.js.map +1 -1
- package/dist/core/ask-types.d.ts +4 -0
- package/dist/core/ask-types.d.ts.map +1 -1
- package/dist/core/ask-types.js +10 -0
- package/dist/core/ask-types.js.map +1 -1
- package/dist/core/cost-calculator.d.ts.map +1 -1
- package/dist/core/cost-calculator.js +35 -13
- package/dist/core/cost-calculator.js.map +1 -1
- package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
- package/dist/core/dashboard-ipc-server.js +89 -16
- package/dist/core/dashboard-ipc-server.js.map +1 -1
- package/dist/core/dashboard-rows.d.ts.map +1 -1
- package/dist/core/dashboard-rows.js +6 -2
- package/dist/core/dashboard-rows.js.map +1 -1
- package/dist/core/dashboard-url.d.ts +6 -5
- package/dist/core/dashboard-url.d.ts.map +1 -1
- package/dist/core/dashboard-url.js +11 -8
- package/dist/core/dashboard-url.js.map +1 -1
- package/dist/core/maintenance.d.ts +11 -8
- package/dist/core/maintenance.d.ts.map +1 -1
- package/dist/core/maintenance.js +45 -20
- package/dist/core/maintenance.js.map +1 -1
- package/dist/core/per-bot-env.d.ts.map +1 -1
- package/dist/core/per-bot-env.js +4 -0
- package/dist/core/per-bot-env.js.map +1 -1
- package/dist/core/session-discovery.d.ts.map +1 -1
- package/dist/core/session-discovery.js +4 -0
- package/dist/core/session-discovery.js.map +1 -1
- package/dist/core/skills/cli-admin-command.d.ts.map +1 -1
- package/dist/core/skills/cli-admin-command.js +8 -2
- package/dist/core/skills/cli-admin-command.js.map +1 -1
- package/dist/core/skills/im-command.d.ts.map +1 -1
- package/dist/core/skills/im-command.js +3 -1
- package/dist/core/skills/im-command.js.map +1 -1
- package/dist/core/skills/sources.d.ts +33 -1
- package/dist/core/skills/sources.d.ts.map +1 -1
- package/dist/core/skills/sources.js +97 -0
- package/dist/core/skills/sources.js.map +1 -1
- package/dist/core/skills/types.d.ts +8 -0
- package/dist/core/skills/types.d.ts.map +1 -1
- package/dist/core/terminal-url.d.ts.map +1 -1
- package/dist/core/terminal-url.js +12 -2
- package/dist/core/terminal-url.js.map +1 -1
- package/dist/core/terminal-write-auth.d.ts +34 -0
- package/dist/core/terminal-write-auth.d.ts.map +1 -0
- package/dist/core/terminal-write-auth.js +76 -0
- package/dist/core/terminal-write-auth.js.map +1 -0
- package/dist/core/tmux-recovery.d.ts +11 -0
- package/dist/core/tmux-recovery.d.ts.map +1 -0
- package/dist/core/tmux-recovery.js +19 -0
- package/dist/core/tmux-recovery.js.map +1 -0
- package/dist/core/types.d.ts +10 -4
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/core/update-check.d.ts +2 -2
- package/dist/core/update-check.js +2 -2
- package/dist/core/worker-pool.d.ts +3 -0
- package/dist/core/worker-pool.d.ts.map +1 -1
- package/dist/core/worker-pool.js +70 -3
- package/dist/core/worker-pool.js.map +1 -1
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +15 -8
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard/auth.d.ts +1 -1
- package/dist/dashboard/auth.d.ts.map +1 -1
- package/dist/dashboard/auth.js +7 -2
- package/dist/dashboard/auth.js.map +1 -1
- package/dist/dashboard/bot-payload.d.ts +3 -0
- package/dist/dashboard/bot-payload.d.ts.map +1 -1
- package/dist/dashboard/bot-payload.js +3 -0
- package/dist/dashboard/bot-payload.js.map +1 -1
- package/dist/dashboard/connector-api.d.ts.map +1 -1
- package/dist/dashboard/connector-api.js +39 -13
- package/dist/dashboard/connector-api.js.map +1 -1
- package/dist/dashboard/history-senders.d.ts +37 -0
- package/dist/dashboard/history-senders.d.ts.map +1 -0
- package/dist/dashboard/history-senders.js +60 -0
- package/dist/dashboard/history-senders.js.map +1 -0
- package/dist/dashboard/roles-batch.d.ts +31 -0
- package/dist/dashboard/roles-batch.d.ts.map +1 -0
- package/dist/dashboard/roles-batch.js +87 -0
- package/dist/dashboard/roles-batch.js.map +1 -0
- package/dist/dashboard/settings-card-model.d.ts +4 -2
- package/dist/dashboard/settings-card-model.d.ts.map +1 -1
- package/dist/dashboard/settings-card-model.js +13 -5
- package/dist/dashboard/settings-card-model.js.map +1 -1
- package/dist/dashboard/settings-write-applier.d.ts +4 -1
- package/dist/dashboard/settings-write-applier.d.ts.map +1 -1
- package/dist/dashboard/settings-write-applier.js +6 -1
- package/dist/dashboard/settings-write-applier.js.map +1 -1
- package/dist/dashboard/skill-install-request.d.ts +4 -0
- package/dist/dashboard/skill-install-request.d.ts.map +1 -1
- package/dist/dashboard/skill-install-request.js +11 -1
- package/dist/dashboard/skill-install-request.js.map +1 -1
- package/dist/dashboard/trigger-api.d.ts +9 -1
- package/dist/dashboard/trigger-api.d.ts.map +1 -1
- package/dist/dashboard/trigger-api.js +48 -10
- package/dist/dashboard/trigger-api.js.map +1 -1
- package/dist/dashboard/web/app.d.ts.map +1 -1
- package/dist/dashboard/web/app.js +286 -271
- package/dist/dashboard/web/app.js.map +1 -1
- package/dist/dashboard/web/bot-defaults-page.d.ts +26 -0
- package/dist/dashboard/web/bot-defaults-page.d.ts.map +1 -1
- package/dist/dashboard/web/bot-defaults-page.js +1408 -12
- package/dist/dashboard/web/bot-defaults-page.js.map +1 -1
- package/dist/dashboard/web/bot-defaults.d.ts +91 -4
- package/dist/dashboard/web/bot-defaults.d.ts.map +1 -1
- package/dist/dashboard/web/bot-defaults.js +43 -2141
- package/dist/dashboard/web/bot-defaults.js.map +1 -1
- package/dist/dashboard/web/bot-onboarding.d.ts +6 -1
- package/dist/dashboard/web/bot-onboarding.d.ts.map +1 -1
- package/dist/dashboard/web/bot-onboarding.js +261 -306
- package/dist/dashboard/web/bot-onboarding.js.map +1 -1
- package/dist/dashboard/web/connectors-page.d.ts +4 -0
- package/dist/dashboard/web/connectors-page.d.ts.map +1 -1
- package/dist/dashboard/web/connectors-page.js +228 -48
- package/dist/dashboard/web/connectors-page.js.map +1 -1
- package/dist/dashboard/web/dashboard-api.d.ts +9 -0
- package/dist/dashboard/web/dashboard-api.d.ts.map +1 -0
- package/dist/dashboard/web/dashboard-api.js +18 -0
- package/dist/dashboard/web/dashboard-api.js.map +1 -0
- package/dist/dashboard/web/dashboard-components.d.ts +92 -0
- package/dist/dashboard/web/dashboard-components.d.ts.map +1 -0
- package/dist/dashboard/web/dashboard-components.js +250 -0
- package/dist/dashboard/web/dashboard-components.js.map +1 -0
- package/dist/dashboard/web/dashboard-routes.d.ts.map +1 -1
- package/dist/dashboard/web/dashboard-routes.js +30 -183
- package/dist/dashboard/web/dashboard-routes.js.map +1 -1
- package/dist/dashboard/web/floating-scrollbars.d.ts +2 -0
- package/dist/dashboard/web/floating-scrollbars.d.ts.map +1 -0
- package/dist/dashboard/web/floating-scrollbars.js +264 -0
- package/dist/dashboard/web/floating-scrollbars.js.map +1 -0
- package/dist/dashboard/web/groups-api.d.ts +36 -0
- package/dist/dashboard/web/groups-api.d.ts.map +1 -0
- package/dist/dashboard/web/groups-api.js +44 -0
- package/dist/dashboard/web/groups-api.js.map +1 -0
- package/dist/dashboard/web/groups-page.d.ts.map +1 -1
- package/dist/dashboard/web/groups-page.js +746 -15
- package/dist/dashboard/web/groups-page.js.map +1 -1
- package/dist/dashboard/web/groups.d.ts +51 -18
- package/dist/dashboard/web/groups.d.ts.map +1 -1
- package/dist/dashboard/web/groups.js +145 -1096
- package/dist/dashboard/web/groups.js.map +1 -1
- package/dist/dashboard/web/i18n.d.ts.map +1 -1
- package/dist/dashboard/web/i18n.js +545 -255
- package/dist/dashboard/web/i18n.js.map +1 -1
- package/dist/dashboard/web/insights-page.d.ts.map +1 -1
- package/dist/dashboard/web/insights-page.js +1047 -14
- package/dist/dashboard/web/insights-page.js.map +1 -1
- package/dist/dashboard/web/insights.d.ts +177 -7
- package/dist/dashboard/web/insights.d.ts.map +1 -1
- package/dist/dashboard/web/insights.js +187 -1926
- package/dist/dashboard/web/insights.js.map +1 -1
- package/dist/dashboard/web/legacy-workflow-page.d.ts +3 -0
- package/dist/dashboard/web/legacy-workflow-page.d.ts.map +1 -0
- package/dist/dashboard/web/legacy-workflow-page.js +717 -0
- package/dist/dashboard/web/legacy-workflow-page.js.map +1 -0
- package/dist/dashboard/web/monitor-room.d.ts.map +1 -1
- package/dist/dashboard/web/monitor-room.js +10 -8
- package/dist/dashboard/web/monitor-room.js.map +1 -1
- package/dist/dashboard/web/monitoring-page.d.ts.map +1 -1
- package/dist/dashboard/web/monitoring-page.js +188 -14
- package/dist/dashboard/web/monitoring-page.js.map +1 -1
- package/dist/dashboard/web/office-page.d.ts.map +1 -1
- package/dist/dashboard/web/office-page.js +11 -23
- package/dist/dashboard/web/office-page.js.map +1 -1
- package/dist/dashboard/web/overview-page.d.ts.map +1 -1
- package/dist/dashboard/web/overview-page.js +141 -147
- package/dist/dashboard/web/overview-page.js.map +1 -1
- package/dist/dashboard/web/overview.d.ts +0 -1
- package/dist/dashboard/web/overview.d.ts.map +1 -1
- package/dist/dashboard/web/overview.js +3 -275
- package/dist/dashboard/web/overview.js.map +1 -1
- package/dist/dashboard/web/preferences.d.ts +1 -6
- package/dist/dashboard/web/preferences.d.ts.map +1 -1
- package/dist/dashboard/web/preferences.js +0 -21
- package/dist/dashboard/web/preferences.js.map +1 -1
- package/dist/dashboard/web/role-batch.d.ts +9 -0
- package/dist/dashboard/web/role-batch.d.ts.map +1 -0
- package/dist/dashboard/web/role-batch.js +42 -0
- package/dist/dashboard/web/role-batch.js.map +1 -0
- package/dist/dashboard/web/roles-page.d.ts.map +1 -1
- package/dist/dashboard/web/roles-page.js +538 -13
- package/dist/dashboard/web/roles-page.js.map +1 -1
- package/dist/dashboard/web/roles.d.ts +98 -1
- package/dist/dashboard/web/roles.d.ts.map +1 -1
- package/dist/dashboard/web/roles.js +117 -903
- package/dist/dashboard/web/roles.js.map +1 -1
- package/dist/dashboard/web/schedules-page.d.ts.map +1 -1
- package/dist/dashboard/web/schedules-page.js +82 -24
- package/dist/dashboard/web/schedules-page.js.map +1 -1
- package/dist/dashboard/web/sessions-kanban.d.ts +67 -0
- package/dist/dashboard/web/sessions-kanban.d.ts.map +1 -0
- package/dist/dashboard/web/sessions-kanban.js +481 -0
- package/dist/dashboard/web/sessions-kanban.js.map +1 -0
- package/dist/dashboard/web/sessions-page.d.ts +4 -0
- package/dist/dashboard/web/sessions-page.d.ts.map +1 -1
- package/dist/dashboard/web/sessions-page.js +1633 -18
- package/dist/dashboard/web/sessions-page.js.map +1 -1
- package/dist/dashboard/web/sessions.d.ts +45 -4
- package/dist/dashboard/web/sessions.d.ts.map +1 -1
- package/dist/dashboard/web/sessions.js +53 -2535
- package/dist/dashboard/web/sessions.js.map +1 -1
- package/dist/dashboard/web/settings-page.d.ts +0 -2
- package/dist/dashboard/web/settings-page.d.ts.map +1 -1
- package/dist/dashboard/web/settings-page.js +127 -117
- package/dist/dashboard/web/settings-page.js.map +1 -1
- package/dist/dashboard/web/skills-page.d.ts +10 -1
- package/dist/dashboard/web/skills-page.d.ts.map +1 -1
- package/dist/dashboard/web/skills-page.js +235 -93
- package/dist/dashboard/web/skills-page.js.map +1 -1
- package/dist/dashboard/web/team-federation-page.d.ts.map +1 -1
- package/dist/dashboard/web/team-federation-page.js +446 -28
- package/dist/dashboard/web/team-federation-page.js.map +1 -1
- package/dist/dashboard/web/team-federation.d.ts +91 -2
- package/dist/dashboard/web/team-federation.d.ts.map +1 -1
- package/dist/dashboard/web/team-federation.js +87 -474
- package/dist/dashboard/web/team-federation.js.map +1 -1
- package/dist/dashboard/web/theme-menu.d.ts +1 -0
- package/dist/dashboard/web/theme-menu.d.ts.map +1 -1
- package/dist/dashboard/web/theme-menu.js +79 -20
- package/dist/dashboard/web/theme-menu.js.map +1 -1
- package/dist/dashboard/web/ui.d.ts +1 -2
- package/dist/dashboard/web/ui.d.ts.map +1 -1
- package/dist/dashboard/web/ui.js +8 -20
- package/dist/dashboard/web/ui.js.map +1 -1
- package/dist/dashboard/web/v3-api.d.ts +16 -0
- package/dist/dashboard/web/v3-api.d.ts.map +1 -0
- package/dist/dashboard/web/v3-api.js +21 -0
- package/dist/dashboard/web/v3-api.js.map +1 -0
- package/dist/dashboard/web/v3-components.d.ts +2 -0
- package/dist/dashboard/web/v3-components.d.ts.map +1 -0
- package/dist/dashboard/web/v3-components.js +290 -0
- package/dist/dashboard/web/v3-components.js.map +1 -0
- package/dist/dashboard/web/v3-model.d.ts +80 -0
- package/dist/dashboard/web/v3-model.d.ts.map +1 -0
- package/dist/dashboard/web/v3-model.js +240 -0
- package/dist/dashboard/web/v3-model.js.map +1 -0
- package/dist/dashboard/web/v3-page.d.ts.map +1 -1
- package/dist/dashboard/web/v3-page.js +2 -22
- package/dist/dashboard/web/v3-page.js.map +1 -1
- package/dist/dashboard/web/v3-terminal.d.ts +14 -0
- package/dist/dashboard/web/v3-terminal.d.ts.map +1 -1
- package/dist/dashboard/web/v3-terminal.js +31 -19
- package/dist/dashboard/web/v3-terminal.js.map +1 -1
- package/dist/dashboard/web/webhook-logs-page.d.ts +16 -0
- package/dist/dashboard/web/webhook-logs-page.d.ts.map +1 -0
- package/dist/dashboard/web/webhook-logs-page.js +195 -0
- package/dist/dashboard/web/webhook-logs-page.js.map +1 -0
- package/dist/dashboard/web/whiteboards-page.d.ts.map +1 -1
- package/dist/dashboard/web/whiteboards-page.js +18 -23
- package/dist/dashboard/web/whiteboards-page.js.map +1 -1
- package/dist/dashboard/web/workflow-version-switch.d.ts +8 -0
- package/dist/dashboard/web/workflow-version-switch.d.ts.map +1 -0
- package/dist/dashboard/web/workflow-version-switch.js +9 -0
- package/dist/dashboard/web/workflow-version-switch.js.map +1 -0
- package/dist/dashboard/web/workflows.d.ts +272 -1
- package/dist/dashboard/web/workflows.d.ts.map +1 -1
- package/dist/dashboard/web/workflows.js +211 -1397
- package/dist/dashboard/web/workflows.js.map +1 -1
- package/dist/dashboard/webhook-routes.d.ts.map +1 -1
- package/dist/dashboard/webhook-routes.js +92 -39
- package/dist/dashboard/webhook-routes.js.map +1 -1
- package/dist/dashboard-web/app.js +1 -65
- package/dist/dashboard-web/brand-logo.png +0 -0
- package/dist/dashboard-web/chunks/bot-defaults-page-HSQ6HR3R.js +1 -0
- package/dist/dashboard-web/chunks/chunk-6TPODDDC.js +1 -0
- package/dist/dashboard-web/chunks/chunk-73EJP2MO.js +1 -0
- package/dist/dashboard-web/chunks/chunk-BRTZFELS.js +1 -0
- package/dist/dashboard-web/chunks/chunk-EVK77ASG.js +1 -0
- package/dist/dashboard-web/chunks/chunk-R3FXBFQH.js +1 -0
- package/dist/dashboard-web/chunks/chunk-VRLL7SNU.js +1 -0
- package/dist/dashboard-web/chunks/chunk-XCPSHD3G.js +37 -0
- package/dist/dashboard-web/chunks/chunk-XJ7BGPJH.js +1 -0
- package/dist/dashboard-web/chunks/chunk-YVRWYGXR.js +1 -0
- package/dist/dashboard-web/chunks/chunk-ZJING6FY.js +66 -0
- package/dist/dashboard-web/chunks/connectors-page-ODUA5UCW.js +1 -0
- package/dist/dashboard-web/chunks/groups-page-OYX5M6NK.js +8 -0
- package/dist/dashboard-web/chunks/insights-page-YCQO6OCR.js +22 -0
- package/dist/dashboard-web/chunks/legacy-workflow-page-XJAUNONP.js +2 -0
- package/dist/dashboard-web/chunks/{monitor-room-RFX4HPS5.js → monitor-room-WTZNYAFV.js} +17 -15
- package/dist/dashboard-web/chunks/monitoring-page-R6LJUK7G.js +2 -0
- package/dist/dashboard-web/chunks/office-page-4OXK3GNR.js +1 -0
- package/dist/dashboard-web/chunks/overview-page-4MVEJY6U.js +1 -0
- package/dist/dashboard-web/chunks/roles-page-NQDW27VV.js +1 -0
- package/dist/dashboard-web/chunks/schedules-page-JRNKYHOX.js +1 -0
- package/dist/dashboard-web/chunks/sessions-page-LF7UVI7B.js +3 -0
- package/dist/dashboard-web/chunks/settings-page-WGW7KQQS.js +2 -0
- package/dist/dashboard-web/chunks/skills-page-AMD4XP3T.js +3 -0
- package/dist/dashboard-web/chunks/team-federation-page-SYG3K4GG.js +1 -0
- package/dist/dashboard-web/chunks/v3-page-6NFFWNUK.js +94 -0
- package/dist/dashboard-web/chunks/whiteboards-page-FBRUK2AS.js +1 -0
- package/dist/dashboard-web/favicon.png +0 -0
- package/dist/dashboard-web/index.html +5 -69
- package/dist/dashboard-web/style.css +18835 -7211
- package/dist/dashboard.js +150 -32
- package/dist/dashboard.js.map +1 -1
- package/dist/global-config.d.ts +2 -2
- package/dist/global-config.d.ts.map +1 -1
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +3 -0
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/zh.d.ts.map +1 -1
- package/dist/i18n/zh.js +3 -0
- package/dist/i18n/zh.js.map +1 -1
- package/dist/im/lark/card-builder.d.ts +7 -5
- package/dist/im/lark/card-builder.d.ts.map +1 -1
- package/dist/im/lark/card-builder.js +10 -7
- package/dist/im/lark/card-builder.js.map +1 -1
- package/dist/im/lark/card-handler.d.ts.map +1 -1
- package/dist/im/lark/card-handler.js +25 -1
- package/dist/im/lark/card-handler.js.map +1 -1
- package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
- package/dist/im/lark/event-dispatcher.js +84 -0
- package/dist/im/lark/event-dispatcher.js.map +1 -1
- package/dist/platform/binding.d.ts +9 -0
- package/dist/platform/binding.d.ts.map +1 -1
- package/dist/platform/binding.js +14 -0
- package/dist/platform/binding.js.map +1 -1
- package/dist/platform/tunnel-client.d.ts.map +1 -1
- package/dist/platform/tunnel-client.js +9 -0
- package/dist/platform/tunnel-client.js.map +1 -1
- package/dist/services/bot-config-store.d.ts +1 -1
- package/dist/services/bot-config-store.d.ts.map +1 -1
- package/dist/services/bot-config-store.js +11 -5
- package/dist/services/bot-config-store.js.map +1 -1
- package/dist/services/file-bridge-path.d.ts +8 -0
- package/dist/services/file-bridge-path.d.ts.map +1 -0
- package/dist/services/file-bridge-path.js +75 -0
- package/dist/services/file-bridge-path.js.map +1 -0
- package/dist/services/grok-paths.d.ts +27 -0
- package/dist/services/grok-paths.d.ts.map +1 -0
- package/dist/services/grok-paths.js +106 -0
- package/dist/services/grok-paths.js.map +1 -0
- package/dist/services/grok-transcript.d.ts +67 -0
- package/dist/services/grok-transcript.d.ts.map +1 -0
- package/dist/services/grok-transcript.js +630 -0
- package/dist/services/grok-transcript.js.map +1 -0
- package/dist/services/hermes-session-filter.d.ts +28 -0
- package/dist/services/hermes-session-filter.d.ts.map +1 -0
- package/dist/services/hermes-session-filter.js +53 -0
- package/dist/services/hermes-session-filter.js.map +1 -0
- package/dist/services/hermes-transcript.d.ts +3 -0
- package/dist/services/hermes-transcript.d.ts.map +1 -1
- package/dist/services/hermes-transcript.js +20 -2
- package/dist/services/hermes-transcript.js.map +1 -1
- package/dist/services/resumable-session-discovery.d.ts +3 -0
- package/dist/services/resumable-session-discovery.d.ts.map +1 -1
- package/dist/services/resumable-session-discovery.js +6 -1
- package/dist/services/resumable-session-discovery.js.map +1 -1
- package/dist/services/skill-registry-store.d.ts +9 -0
- package/dist/services/skill-registry-store.d.ts.map +1 -1
- package/dist/services/skill-registry-store.js +304 -1
- package/dist/services/skill-registry-store.js.map +1 -1
- package/dist/services/structured-bridge-clis.d.ts +29 -0
- package/dist/services/structured-bridge-clis.d.ts.map +1 -0
- package/dist/services/structured-bridge-clis.js +76 -0
- package/dist/services/structured-bridge-clis.js.map +1 -0
- package/dist/services/trigger-log-store.d.ts +59 -0
- package/dist/services/trigger-log-store.d.ts.map +1 -1
- package/dist/services/trigger-log-store.js +81 -10
- package/dist/services/trigger-log-store.js.map +1 -1
- package/dist/services/usage-ledger.d.ts +4 -1
- package/dist/services/usage-ledger.d.ts.map +1 -1
- package/dist/services/usage-ledger.js +48 -10
- package/dist/services/usage-ledger.js.map +1 -1
- package/dist/services/webhook-audit.d.ts +10 -0
- package/dist/services/webhook-audit.d.ts.map +1 -0
- package/dist/services/webhook-audit.js +116 -0
- package/dist/services/webhook-audit.js.map +1 -0
- package/dist/setup/bot-config-editor.d.ts.map +1 -1
- package/dist/setup/bot-config-editor.js +2 -0
- package/dist/setup/bot-config-editor.js.map +1 -1
- package/dist/setup/ensure-tmux.d.ts +26 -12
- package/dist/setup/ensure-tmux.d.ts.map +1 -1
- package/dist/setup/ensure-tmux.js +85 -18
- package/dist/setup/ensure-tmux.js.map +1 -1
- package/dist/skills/definitions.d.ts.map +1 -1
- package/dist/skills/definitions.js +14 -1
- package/dist/skills/definitions.js.map +1 -1
- package/dist/skills/injection-mode.d.ts +16 -0
- package/dist/skills/injection-mode.d.ts.map +1 -1
- package/dist/skills/injection-mode.js +25 -0
- package/dist/skills/injection-mode.js.map +1 -1
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/global-install.d.ts +22 -0
- package/dist/utils/global-install.d.ts.map +1 -0
- package/dist/utils/global-install.js +106 -0
- package/dist/utils/global-install.js.map +1 -0
- package/dist/utils/install-diagnostics.d.ts +1 -1
- package/dist/utils/install-diagnostics.d.ts.map +1 -1
- package/dist/utils/install-diagnostics.js +6 -4
- package/dist/utils/install-diagnostics.js.map +1 -1
- package/dist/utils/install-info.d.ts +2 -0
- package/dist/utils/install-info.d.ts.map +1 -1
- package/dist/utils/install-info.js +10 -4
- package/dist/utils/install-info.js.map +1 -1
- package/dist/worker.js +293 -172
- package/dist/worker.js.map +1 -1
- package/dist/workflows/events/payloads.d.ts +10 -10
- package/dist/workflows/events/schema.d.ts +28 -28
- package/package.json +8 -7
- package/dist/dashboard/web/connectors.d.ts +0 -2
- package/dist/dashboard/web/connectors.d.ts.map +0 -1
- package/dist/dashboard/web/connectors.js +0 -2
- package/dist/dashboard/web/connectors.js.map +0 -1
- package/dist/dashboard/web/office.d.ts +0 -2
- package/dist/dashboard/web/office.d.ts.map +0 -1
- package/dist/dashboard/web/office.js +0 -2
- package/dist/dashboard/web/office.js.map +0 -1
- package/dist/dashboard/web/schedules.d.ts +0 -2
- package/dist/dashboard/web/schedules.d.ts.map +0 -1
- package/dist/dashboard/web/schedules.js +0 -2
- package/dist/dashboard/web/schedules.js.map +0 -1
- package/dist/dashboard/web/settings.d.ts +0 -2
- package/dist/dashboard/web/settings.d.ts.map +0 -1
- package/dist/dashboard/web/settings.js +0 -2
- package/dist/dashboard/web/settings.js.map +0 -1
- package/dist/dashboard/web/skills.d.ts +0 -2
- package/dist/dashboard/web/skills.d.ts.map +0 -1
- package/dist/dashboard/web/skills.js +0 -2
- package/dist/dashboard/web/skills.js.map +0 -1
- package/dist/dashboard/web/skin-intro.d.ts +0 -4
- package/dist/dashboard/web/skin-intro.d.ts.map +0 -1
- package/dist/dashboard/web/skin-intro.js +0 -49
- package/dist/dashboard/web/skin-intro.js.map +0 -1
- package/dist/dashboard/web/v3.d.ts +0 -3
- package/dist/dashboard/web/v3.d.ts.map +0 -1
- package/dist/dashboard/web/v3.js +0 -539
- package/dist/dashboard/web/v3.js.map +0 -1
- package/dist/dashboard/web/whiteboards.d.ts +0 -2
- package/dist/dashboard/web/whiteboards.d.ts.map +0 -1
- package/dist/dashboard/web/whiteboards.js +0 -2
- package/dist/dashboard/web/whiteboards.js.map +0 -1
- package/dist/dashboard-web/chunks/bot-defaults-page-OCIHPGEU.js +0 -438
- package/dist/dashboard-web/chunks/chunk-3N2PPQVD.js +0 -1
- package/dist/dashboard-web/chunks/chunk-3UJYRR2Q.js +0 -37
- package/dist/dashboard-web/chunks/chunk-5E3MJJL4.js +0 -1
- package/dist/dashboard-web/chunks/chunk-7SZRL6FY.js +0 -1
- package/dist/dashboard-web/chunks/chunk-JTSE5VP6.js +0 -54
- package/dist/dashboard-web/chunks/chunk-LXIK7OUJ.js +0 -1
- package/dist/dashboard-web/chunks/chunk-PE6W3C2C.js +0 -1
- package/dist/dashboard-web/chunks/chunk-QW54DWU3.js +0 -325
- package/dist/dashboard-web/chunks/connectors-IGETYWCP.js +0 -1
- package/dist/dashboard-web/chunks/groups-page-MYBS4ZYJ.js +0 -207
- package/dist/dashboard-web/chunks/insights-page-UPA32V2S.js +0 -309
- package/dist/dashboard-web/chunks/monitoring-page-7T3BESZ2.js +0 -1
- package/dist/dashboard-web/chunks/office-page-6DXYOG55.js +0 -1
- package/dist/dashboard-web/chunks/overview-page-LJSBCQW4.js +0 -1
- package/dist/dashboard-web/chunks/roles-page-ESURTVQH.js +0 -98
- package/dist/dashboard-web/chunks/schedules-LML2ISOT.js +0 -1
- package/dist/dashboard-web/chunks/sessions-YB73XOTU.js +0 -1
- package/dist/dashboard-web/chunks/sessions-page-MCO5QR7Z.js +0 -1
- package/dist/dashboard-web/chunks/settings-page-OSDKNVS3.js +0 -2
- package/dist/dashboard-web/chunks/skills-page-PXBZJ6P6.js +0 -2
- package/dist/dashboard-web/chunks/team-federation-page-TTPVHFPX.js +0 -10
- package/dist/dashboard-web/chunks/v3-page-FVPUL665.js +0 -149
- package/dist/dashboard-web/chunks/whiteboards-page-HLCTYSSV.js +0 -1
- package/dist/dashboard-web/chunks/workflows-FCPM4S4D.js +0 -184
- package/dist/dashboard-web/skins/bluearchive-hero.webp +0 -0
- package/dist/dashboard-web/skins/dragonball-goku.webp +0 -0
- package/dist/dashboard-web/skins/dragonball-wukong.webp +0 -0
- package/dist/dashboard-web/skins/genshin-breeze.webp +0 -0
- package/dist/dashboard-web/skins/ikun-hero.webp +0 -0
- package/dist/dashboard-web/skins/prts-priestess.webp +0 -0
- package/dist/dashboard-web/skins/zzz-hero.webp +0 -0
- package/dist/dashboard-web/skins/zzz-pattern.svg +0 -25
|
@@ -1,24 +1,755 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useRef } from 'react';
|
|
3
|
-
import { loadingHtml } from './ui.js';
|
|
4
|
-
import { useT } from './react-hooks.js';
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { memo, useCallback, useEffect, useMemo, useRef, useState, } from 'react';
|
|
5
3
|
import { mountReactPage } from './react-mount.js';
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
import { useT } from './react-hooks.js';
|
|
5
|
+
import { botOrbStyle, chatAvatarUrlFor } from './ui.js';
|
|
6
|
+
import { CreateActionButton, DropdownMenu, LoadingState, OverviewList, OverviewListItem, OverviewListMain, OverviewListTail, RefreshIconButton, } from './dashboard-components.js';
|
|
7
|
+
import { hasExplicitChatRole, summarizeGroupProfileMatches, } from './role-profile-match.js';
|
|
8
|
+
import { allExpectedInChat, availableBotsForPicker, collectGroupProfileEntries, emptyGroupsSnapshot, fetchGroupsSnapshot, fetchRoleProfileSummaries, filterGroupChats, injectOptimisticChat, isValidProfileId, loadGroupRoleProfileContext, paginateGroupRows, roleKey, roleProfileBootstrapStatus, summarizeAddBotsResult, suggestRoleProfileIdFromChat, } from './groups.js';
|
|
9
|
+
function emptyRoleContext() {
|
|
10
|
+
return {
|
|
11
|
+
profiles: [],
|
|
12
|
+
entriesById: new Map(),
|
|
13
|
+
groupRoleContentByBot: new Map(),
|
|
14
|
+
loaded: false,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function orbVars(name) {
|
|
18
|
+
const style = {};
|
|
19
|
+
for (const part of botOrbStyle(name).split(';')) {
|
|
20
|
+
if (!part)
|
|
21
|
+
continue;
|
|
22
|
+
const i = part.indexOf(':');
|
|
23
|
+
if (i <= 0)
|
|
24
|
+
continue;
|
|
25
|
+
style[part.slice(0, i)] = part.slice(i + 1);
|
|
26
|
+
}
|
|
27
|
+
return style;
|
|
28
|
+
}
|
|
29
|
+
function ChatAvatar(props) {
|
|
30
|
+
const chat = props.chat;
|
|
31
|
+
const url = chat.avatar ?? chatAvatarUrlFor(chat.chatId);
|
|
32
|
+
const [broken, setBroken] = useState(false);
|
|
33
|
+
useEffect(() => { setBroken(false); }, [url]);
|
|
34
|
+
const name = chat.name ?? chat.chatId;
|
|
35
|
+
const hasImage = !!url && !broken;
|
|
36
|
+
return (_jsx("span", { className: `orb-avatar orb-square orb-avatar-sm${hasImage ? ' orb-has-img' : ''}`, style: orbVars(name), "aria-hidden": "true", children: hasImage ? (_jsx("img", { className: "orb-img", src: url, alt: "", decoding: "async", referrerPolicy: "no-referrer", onError: () => setBroken(true) })) : null }));
|
|
37
|
+
}
|
|
38
|
+
function DialogError(props) {
|
|
39
|
+
return (_jsxs("p", { className: "hint-warn", children: [_jsx("strong", { children: props.title }), _jsx("br", {}), _jsx("small", { children: String(props.reason ?? 'unknown') })] }));
|
|
40
|
+
}
|
|
41
|
+
function BotCheckboxes(props) {
|
|
42
|
+
return (_jsx(_Fragment, { children: availableBotsForPicker(props.bots, props.excludeIds).map(bot => (_jsxs("label", { className: "checkbox-row", children: [_jsx("input", { type: "checkbox", name: "bot", value: bot.larkAppId }), _jsxs("span", { className: "checkbox-row-main", children: [_jsx("strong", { children: bot.botName ?? bot.larkAppId }), _jsxs("small", { children: ["(", bot.larkAppId, ")"] })] })] }, bot.larkAppId))) }));
|
|
43
|
+
}
|
|
44
|
+
function AddBotsResult(props) {
|
|
45
|
+
const summary = props.summary;
|
|
46
|
+
if (!summary.rows.length) {
|
|
47
|
+
return _jsx("p", { className: "hint-warn", children: "\u6CA1\u6709\u8FD4\u56DE\u6DFB\u52A0\u7ED3\u679C\u3002" });
|
|
48
|
+
}
|
|
49
|
+
return (_jsxs("div", { className: summary.failed ? 'hint-warn' : 'hint-ok', children: [_jsxs("strong", { children: ["\u6DFB\u52A0\u7ED3\u679C\uFF1A\u6210\u529F ", summary.okCount, "/", summary.rows.length, summary.failed ? `,失败 ${summary.failed}` : ''] }), _jsx("ul", { children: summary.rows.map((row, index) => {
|
|
50
|
+
const id = String(row?.id ?? '?');
|
|
51
|
+
return (_jsxs("li", { children: [_jsx("code", { children: id }), ": ", row?.ok ? 'OK' : `failed (${String(row?.error ?? 'unknown')})`] }, `${id}-${index}`));
|
|
52
|
+
}) })] }));
|
|
53
|
+
}
|
|
54
|
+
function GroupProfileStatus(props) {
|
|
55
|
+
const { chat, context, tr } = props;
|
|
56
|
+
if (!context.profiles.length || !context.loaded)
|
|
57
|
+
return null;
|
|
58
|
+
const rolesByBot = new Map();
|
|
59
|
+
for (const bot of chat.memberBots ?? []) {
|
|
60
|
+
if (!bot?.inChat)
|
|
61
|
+
continue;
|
|
62
|
+
rolesByBot.set(bot.larkAppId, context.groupRoleContentByBot.get(roleKey(bot.larkAppId, chat.chatId)) ?? null);
|
|
63
|
+
}
|
|
64
|
+
if (!hasExplicitChatRole(rolesByBot))
|
|
65
|
+
return null;
|
|
66
|
+
const matches = summarizeGroupProfileMatches(chat.memberBots ?? [], context.profiles, context.entriesById, rolesByBot);
|
|
67
|
+
const best = matches[0];
|
|
68
|
+
if (!best) {
|
|
69
|
+
return _jsx("div", { className: "g-profile-status muted", children: tr('groups.profileStatusUnmatched') });
|
|
70
|
+
}
|
|
71
|
+
const key = best.kind === 'full' ? 'groups.profileStatusFullChat' : 'groups.profileStatusPartial';
|
|
72
|
+
return (_jsx("div", { className: `g-profile-status ${best.kind}`, children: tr(key, {
|
|
73
|
+
name: best.profileId,
|
|
74
|
+
matched: best.matched,
|
|
75
|
+
total: best.total,
|
|
76
|
+
chat: best.chatMatched,
|
|
77
|
+
}) }));
|
|
78
|
+
}
|
|
79
|
+
function groupBotStatus(member) {
|
|
80
|
+
if (!member)
|
|
81
|
+
return 'unknown';
|
|
82
|
+
if (member.error)
|
|
83
|
+
return 'error';
|
|
84
|
+
return member.inChat ? 'in' : 'out';
|
|
85
|
+
}
|
|
86
|
+
function groupBotStatusLabel(status, tr) {
|
|
87
|
+
switch (status) {
|
|
88
|
+
case 'in': return tr('groups.botStatusIn');
|
|
89
|
+
case 'out': return tr('groups.botStatusOut');
|
|
90
|
+
case 'error': return tr('groups.botStatusError');
|
|
91
|
+
case 'unknown':
|
|
92
|
+
default:
|
|
93
|
+
return tr('groups.botStatusUnknown');
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function GroupBotCoverage(props) {
|
|
97
|
+
const members = new Map((props.chat.memberBots ?? []).map(member => [member.larkAppId, member]));
|
|
98
|
+
return (_jsx("div", { className: "groups-bot-strip", "aria-label": props.tr('groups.botCoverage'), children: props.bots.map(bot => {
|
|
99
|
+
const member = members.get(bot.larkAppId);
|
|
100
|
+
const status = groupBotStatus(member);
|
|
101
|
+
const label = groupBotStatusLabel(status, props.tr);
|
|
102
|
+
const name = bot.botName ?? bot.larkAppId;
|
|
103
|
+
return (_jsxs("span", { className: `groups-bot-pill groups-bot-${status}`, title: `${name}: ${label}${member?.error ? ` (${String(member.error)})` : ''}`, children: [_jsx("i", { "aria-hidden": "true" }), _jsx("span", { className: "groups-bot-name", children: name }), _jsx("span", { className: "groups-bot-state", children: label })] }, bot.larkAppId));
|
|
104
|
+
}) }));
|
|
105
|
+
}
|
|
106
|
+
const GroupListRow = memo(function GroupListRow(props) {
|
|
107
|
+
const { chat, tr } = props;
|
|
108
|
+
const members = chat.memberBots ?? [];
|
|
109
|
+
const inCount = members.filter(member => member.inChat).length;
|
|
110
|
+
return (_jsxs(OverviewListItem, { kind: "group", className: "groups-list-row", "data-chat": chat.chatId, children: [_jsx(ChatAvatar, { chat: chat }), _jsxs(OverviewListMain, { children: [_jsxs("div", { className: "groups-row-head", children: [_jsx("b", { children: chat.name ?? chat.chatId }), _jsxs("span", { className: "groups-row-meta", children: [_jsx("span", { className: "groups-row-tag", children: _jsx("code", { children: chat.chatId }) }), chat.ownerId ? (_jsxs("span", { className: "groups-row-tag groups-row-owner-tag", children: [_jsx("span", { children: tr('groups.owner') }), _jsx("code", { children: chat.ownerId })] })) : null] })] }), _jsx(GroupProfileStatus, { chat: chat, context: props.roleContext, tr: tr })] }), _jsx("span", { className: "groups-row-count", children: tr('groups.memberSummary', { count: inCount, total: props.bots.length }) }), _jsxs("div", { className: "groups-row-lower", children: [_jsx(GroupBotCoverage, { chat: chat, bots: props.bots, tr: tr }), _jsxs(OverviewListTail, { children: [_jsx(CreateActionButton, { className: "add-bots", onClick: () => props.onAddBots(chat), children: tr('groups.addBots') }), _jsx("button", { className: "save-profile", type: "button", onClick: () => props.onSaveProfile(chat), children: tr('groups.saveAsProfile') }), _jsx("button", { className: "manage-chat", type: "button", onClick: () => props.onManage(chat), children: tr('groups.manage') })] })] })] }));
|
|
111
|
+
});
|
|
112
|
+
function CreateDialog(props) {
|
|
113
|
+
const { tr } = props;
|
|
114
|
+
const [submitting, setSubmitting] = useState(false);
|
|
115
|
+
const [error, setError] = useState(null);
|
|
116
|
+
const [success, setSuccess] = useState(null);
|
|
117
|
+
const [copied, setCopied] = useState(false);
|
|
118
|
+
const [roleProfileId, setRoleProfileId] = useState('');
|
|
119
|
+
async function submit(ev) {
|
|
120
|
+
ev.preventDefault();
|
|
121
|
+
const fd = new FormData(ev.currentTarget);
|
|
122
|
+
const name = String(fd.get('name') ?? '').trim();
|
|
123
|
+
const bindWorkingDir = String(fd.get('bindWorkingDir') ?? '').trim();
|
|
124
|
+
const roleProfileId = String(fd.get('roleProfileId') ?? '').trim();
|
|
125
|
+
const ids = fd.getAll('bot');
|
|
126
|
+
if (ids.length === 0) {
|
|
127
|
+
setError({ title: '请选择 bot', reason: '至少选择一个 bot 后再创建群聊。' });
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
setSubmitting(true);
|
|
131
|
+
setError(null);
|
|
132
|
+
try {
|
|
133
|
+
const r = await fetch('/api/groups/create', {
|
|
134
|
+
method: 'POST',
|
|
135
|
+
headers: { 'content-type': 'application/json' },
|
|
136
|
+
body: JSON.stringify({
|
|
137
|
+
name: name || undefined,
|
|
138
|
+
larkAppIds: ids,
|
|
139
|
+
bindWorkingDir: bindWorkingDir || undefined,
|
|
140
|
+
roleProfileId: roleProfileId || undefined,
|
|
141
|
+
}),
|
|
142
|
+
});
|
|
143
|
+
const respBody = await r.json().catch(() => ({ ok: false, error: `HTTP ${r.status}` }));
|
|
144
|
+
if (respBody.ok && respBody.chatId) {
|
|
145
|
+
setSuccess(respBody);
|
|
146
|
+
props.onCreated(respBody, ids, name);
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
setError({ title: '创建失败', reason: respBody.error ?? `HTTP ${r.status}` });
|
|
150
|
+
setSubmitting(false);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
catch (err) {
|
|
154
|
+
setError({ title: '网络错误', reason: err });
|
|
155
|
+
setSubmitting(false);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (success) {
|
|
159
|
+
const chatId = String(success.chatId);
|
|
160
|
+
const appLink = typeof success.shareLink === 'string' && success.shareLink
|
|
161
|
+
? success.shareLink
|
|
162
|
+
: `https://applink.feishu.cn/client/chat/open?openChatId=${encodeURIComponent(chatId)}`;
|
|
163
|
+
const invalidBots = (success.invalidBotIds ?? []);
|
|
164
|
+
const invalidUsers = (success.invalidUserIds ?? []);
|
|
165
|
+
const binds = Array.isArray(success.oncallBindings) ? success.oncallBindings : [];
|
|
166
|
+
const bindOk = binds.filter(b => b?.ok).length;
|
|
167
|
+
const bindFailed = binds.filter(b => !b?.ok);
|
|
168
|
+
const profileStatus = roleProfileBootstrapStatus(typeof success.roleProfileId === 'string' ? success.roleProfileId : '', success.roleProfileBootstrapMessageId, success.roleProfileBootstrapError);
|
|
169
|
+
return (_jsxs("article", { className: "g-create-dialog g-create-success", children: [_jsx("header", { children: _jsx("h3", { children: tr('groups.successTitle') }) }), _jsxs("p", { children: [_jsx("b", { children: "chatId:" }), " ", _jsx("code", { children: chatId }), ' ', _jsx("button", { type: "button", "data-copy": chatId, onClick: () => {
|
|
170
|
+
void navigator.clipboard.writeText(chatId);
|
|
171
|
+
setCopied(true);
|
|
172
|
+
props.setTimer(() => setCopied(false), 800);
|
|
173
|
+
}, children: copied ? tr('sessions.copied') : tr('sessions.copy') })] }), _jsxs("p", { children: [_jsx("b", { children: "\u521B\u5EFA\u8005:" }), " ", _jsx("code", { children: String(success.creator ?? '?') })] }), _jsx(CreateInviteNote, { resp: success }), binds.length > 0 ? (bindFailed.length === 0 ? (_jsxs("p", { className: "hint-ok", children: ["\u5DF2\u7ED1\u5B9A\u76EE\u5F55\uFF1A", _jsx("code", { children: String(success.bindResolvedPath ?? '') }), "\uFF08", bindOk, "/", binds.length, " bots\uFF09"] })) : (_jsxs("p", { className: "hint-warn", children: ["\u76EE\u5F55\u7ED1\u5B9A\u90E8\u5206\u5931\u8D25\uFF1A\u6210\u529F ", bindOk, "/", binds.length, "\u3002", bindFailed.map((b, index) => (_jsxs("span", { children: [_jsx("br", {}), _jsx("code", { children: String(b?.larkAppId ?? '?') }), ": ", String(b?.error ?? 'unknown')] }, `${b?.larkAppId ?? '?'}-${index}`)))] }))) : null, profileStatus ? _jsx("p", { className: profileStatus.kind === 'ok' ? 'hint-ok' : 'hint-warn', children: profileStatus.text }) : null, invalidBots.length || invalidUsers.length ? (_jsxs("ul", { children: [invalidBots.length ? _jsxs("li", { children: ["\u65E0\u6548 bot id: ", _jsx("code", { children: invalidBots.join(', ') })] }) : null, invalidUsers.length ? _jsxs("li", { children: ["\u65E0\u6548\u7528\u6237 open_id: ", _jsx("code", { children: invalidUsers.join(', ') })] }) : null] })) : null, _jsxs("div", { className: "actions", children: [_jsx("button", { type: "button", id: "g-create-close", onClick: props.onClose, children: tr('sessions.dismiss') }), _jsx("a", { className: "btn-link primary", href: appLink, target: "_blank", rel: "noopener", children: tr('groups.openGroup') })] })] }));
|
|
174
|
+
}
|
|
175
|
+
return (_jsxs("article", { className: "g-create-dialog", children: [_jsxs("header", { className: "g-create-head", children: [_jsx("h3", { children: tr('groups.createTitle') }), _jsx("p", { children: tr('groups.createHelp') })] }), _jsxs("form", { id: "g-createform", className: "g-create-form", onSubmit: ev => void submit(ev), children: [_jsxs("fieldset", { className: "g-modal-field g-create-bots", children: [_jsx("legend", { children: tr('groups.botPicker') }), _jsx("div", { className: "g-bot-picker", children: _jsx(BotCheckboxes, { bots: props.bots }) })] }), _jsxs("div", { className: "g-create-fields", children: [_jsxs("fieldset", { className: "g-modal-field", children: [_jsx("legend", { children: tr('groups.name') }), _jsx("input", { type: "text", name: "name", placeholder: tr('groups.namePlaceholder'), maxLength: 60 })] }), _jsxs("fieldset", { className: "g-modal-field", children: [_jsx("legend", { children: tr('groups.bindDir') }), _jsx("input", { type: "text", name: "bindWorkingDir", placeholder: "e.g. ~/projects/botmux" }), _jsx("small", { children: tr('groups.bindDirHelp') })] }), _jsxs("fieldset", { className: "g-modal-field g-profile-field", children: [_jsx("legend", { children: tr('groups.roleProfile') }), _jsx("input", { type: "hidden", name: "roleProfileId", value: roleProfileId }), _jsx(DropdownMenu, { className: "g-profile-menu", ariaLabel: tr('groups.roleProfile'), label: roleProfileId || tr('groups.roleProfileNone'), value: roleProfileId, options: [
|
|
176
|
+
{ value: '', label: tr('groups.roleProfileNone') },
|
|
177
|
+
...props.roleProfiles.map(profile => ({ value: profile.profileId, label: profile.profileId })),
|
|
178
|
+
], onChange: setRoleProfileId }), _jsx("small", { children: tr('groups.roleProfileHelp') })] })] }), _jsx("div", { className: "g-create-status", "data-create-status": true, "aria-live": "polite", children: error ? _jsx(DialogError, { ...error }) : null }), _jsxs("div", { className: "actions g-create-actions", children: [_jsx("button", { type: "button", id: "g-create-cancel", onClick: props.onClose, children: tr('groups.cancel') }), _jsx("button", { type: "submit", className: "primary", disabled: submitting, children: submitting ? _jsxs(_Fragment, { children: [_jsx("i", { className: "button-spinner", "aria-hidden": "true" }), tr('groups.createSubmitting')] }) : tr('groups.createSubmit') })] })] })] }));
|
|
179
|
+
}
|
|
180
|
+
function CreateInviteNote(props) {
|
|
181
|
+
const resp = props.resp;
|
|
182
|
+
const auto = resp.autoInvitedOpenId;
|
|
183
|
+
const rejected = !!resp.autoInviteRejected;
|
|
184
|
+
const ownerTo = resp.ownerTransferredTo;
|
|
185
|
+
const transferErr = resp.transferError;
|
|
186
|
+
const notifyMsgId = resp.notifyMessageId;
|
|
187
|
+
const notifyErr = resp.notifyError;
|
|
188
|
+
if (auto) {
|
|
189
|
+
return (_jsxs("p", { className: "hint-ok", children: ["\u5DF2\u81EA\u52A8\u9080\u8BF7\u4F60\uFF08", _jsx("code", { children: auto }), "\uFF09\u4F5C\u4E3A\u6210\u5458\u3002", ownerTo ? _jsxs(_Fragment, { children: [_jsx("br", {}), _jsx("small", { children: "\u7FA4\u4E3B\u5DF2\u4ECE\u673A\u5668\u4EBA\u8F6C\u8BA9\u7ED9\u4F60\u3002" })] }) : null, transferErr ? _jsxs(_Fragment, { children: [_jsx("br", {}), _jsxs("small", { className: "hint-warn-inline", children: ["\u26A0 \u81EA\u52A8\u8F6C\u8BA9\u7FA4\u4E3B\u5931\u8D25\uFF08", transferErr, "\uFF09\uFF0C\u4F60\u73B0\u5728\u662F\u6210\u5458\u4F46\u7FA4\u4E3B\u4ECD\u662F\u673A\u5668\u4EBA\u3002"] })] }) : null, notifyMsgId ? _jsxs(_Fragment, { children: [_jsx("br", {}), _jsxs("small", { children: ["\u673A\u5668\u4EBA\u5DF2\u5728\u7FA4\u91CC @ \u4E86\u4F60\uFF08\u6D88\u606F id ", _jsx("code", { children: notifyMsgId }), "\uFF09\uFF0C\u770B\u98DE\u4E66\u901A\u77E5\u5C31\u80FD\u8FDB\u7FA4\u3002"] })] }) : null, notifyErr ? _jsxs(_Fragment, { children: [_jsx("br", {}), _jsxs("small", { className: "hint-warn-inline", children: ["\u26A0 \u81EA\u52A8 @ \u901A\u77E5\u5931\u8D25\uFF08", notifyErr, "\uFF09\uFF0C\u65B0\u7FA4\u53EF\u80FD\u4E0D\u4F1A\u4E3B\u52A8\u51FA\u73B0\u5728\u4F60\u4FA7\u8FB9\u680F\uFF0C\u5EFA\u8BAE\u4ECE\u4E0B\u9762\u6309\u94AE\u8DF3\u8FDB\u53BB\u3002"] })] }) : null] }));
|
|
190
|
+
}
|
|
191
|
+
if (rejected) {
|
|
192
|
+
return (_jsxs("p", { className: "hint-warn", children: ["\u98DE\u4E66\u62D2\u7EDD\u4E86\u81EA\u52A8\u9080\u8BF7\uFF08\u4F60\u7684 open_id \u5728\u521B\u5EFA\u8005 bot \u7684 scope \u4E0B\u4E0D\u53EF\u7528\uFF09\u3002", _jsx("strong", { children: "\u4F60\u76EE\u524D\u4E0D\u662F\u65B0\u7FA4\u6210\u5458" }), "\uFF0C\u9700\u8981\u8BA9\u7FA4\u91CC\u7684\u67D0\u4E2A\u673A\u5668\u4EBA\u624B\u52A8\u628A\u4F60\u52A0\u8FDB\u6765\u3002"] }));
|
|
193
|
+
}
|
|
194
|
+
return (_jsxs("p", { className: "hint-warn", children: ["\u6CA1\u5728 dashboard \u7F13\u5B58\u91CC\u627E\u5230 ownerOpenId\uFF0C", _jsx("strong", { children: "\u6CA1\u6709\u81EA\u52A8\u9080\u8BF7\u4F60" }), "\u3002\u70B9\u5F00\u4E0B\u9762\u94FE\u63A5\u524D\uFF0C\u5148\u8BA9\u7FA4\u91CC\u4EFB\u4E00\u673A\u5668\u4EBA\u624B\u52A8\u628A\u4F60\u52A0\u8FDB\u53BB\u3002"] }));
|
|
195
|
+
}
|
|
196
|
+
function AddBotsDialog(props) {
|
|
197
|
+
const { chat, tr } = props;
|
|
198
|
+
const [submitting, setSubmitting] = useState(false);
|
|
199
|
+
const [error, setError] = useState(null);
|
|
200
|
+
const [summary, setSummary] = useState(null);
|
|
201
|
+
const inChatSet = useMemo(() => new Set((chat.memberBots ?? []).filter(member => member.inChat).map(member => member.larkAppId)), [chat]);
|
|
202
|
+
async function submit(ev) {
|
|
203
|
+
ev.preventDefault();
|
|
204
|
+
const fd = new FormData(ev.currentTarget);
|
|
205
|
+
const ids = fd.getAll('bot');
|
|
206
|
+
if (ids.length === 0) {
|
|
207
|
+
setError({ title: '请选择 bot', reason: '至少选择一个 bot 后再添加。' });
|
|
208
|
+
setSummary(null);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
setSubmitting(true);
|
|
212
|
+
setError(null);
|
|
213
|
+
setSummary(null);
|
|
214
|
+
try {
|
|
215
|
+
const r = await fetch(`/api/groups/${encodeURIComponent(chat.chatId)}/add-bots`, {
|
|
216
|
+
method: 'POST',
|
|
217
|
+
headers: { 'content-type': 'application/json' },
|
|
218
|
+
body: JSON.stringify({ larkAppIds: ids }),
|
|
219
|
+
});
|
|
220
|
+
const respBody = await r.json();
|
|
221
|
+
if (respBody.error === 'no_proxy_bot') {
|
|
222
|
+
setError({
|
|
223
|
+
title: '无法添加 bot',
|
|
224
|
+
reason: '当前群里没有可代理操作的 bot。请先在飞书里手动拉入一个 bot,然后重试。',
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
else if (respBody.result) {
|
|
228
|
+
const result = summarizeAddBotsResult(respBody.result);
|
|
229
|
+
try {
|
|
230
|
+
await props.onReloadGroups({ force: true });
|
|
231
|
+
setSummary({ result });
|
|
232
|
+
}
|
|
233
|
+
catch (err) {
|
|
234
|
+
setSummary({ result, refreshError: `添加结果已返回,但刷新群组列表失败:${err}` });
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
setError({ title: '响应异常', reason: JSON.stringify(respBody) });
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
catch (err) {
|
|
242
|
+
setError({ title: '网络错误', reason: err });
|
|
243
|
+
}
|
|
244
|
+
finally {
|
|
245
|
+
setSubmitting(false);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return (_jsxs("article", { className: "g-add-bots-dialog", children: [_jsx("header", { children: _jsxs("h3", { children: [tr('groups.addBots'), " \u00B7 ", chat.name ?? chat.chatId] }) }), _jsx("p", { children: tr('groups.createHelp') }), _jsxs("form", { id: "g-addform", onSubmit: ev => void submit(ev), children: [_jsx(BotCheckboxes, { bots: props.bots, excludeIds: inChatSet }), _jsxs("div", { "data-add-status": true, "aria-live": "polite", children: [error ? _jsx(DialogError, { ...error }) : null, summary ? (_jsxs(_Fragment, { children: [_jsx(AddBotsResult, { summary: summary.result }), summary.refreshError ? _jsx(DialogError, { title: "\u5237\u65B0\u5931\u8D25", reason: summary.refreshError }) : null] })) : null] }), _jsxs("div", { className: "actions", children: [_jsx("button", { type: "button", id: "g-cancel", onClick: props.onClose, children: tr('groups.cancel') }), _jsx("button", { type: "submit", className: "primary", disabled: submitting, children: submitting ? 'Adding...' : tr('groups.addBots') })] })] })] }));
|
|
249
|
+
}
|
|
250
|
+
function SaveProfileDialog(props) {
|
|
251
|
+
const { tr } = props;
|
|
252
|
+
const [entries, setEntries] = useState([]);
|
|
253
|
+
const [profiles, setProfiles] = useState([]);
|
|
254
|
+
const [loadingSnapshot, setLoadingSnapshot] = useState(true);
|
|
255
|
+
const [loadError, setLoadError] = useState(null);
|
|
256
|
+
const sortedProfiles = useMemo(() => [...profiles].sort((a, b) => a.profileId.localeCompare(b.profileId)), [profiles]);
|
|
257
|
+
const hasExistingProfiles = sortedProfiles.length > 0;
|
|
258
|
+
const emptyCount = entries.filter(entry => entry.status === 'empty').length;
|
|
259
|
+
const failedCount = entries.filter(entry => entry.status === 'error').length;
|
|
260
|
+
const canSubmitSnapshot = !loadingSnapshot && !loadError && entries.length > 0 && failedCount === 0;
|
|
261
|
+
const [selectedMode, setSelectedMode] = useState('new');
|
|
262
|
+
const [profileId, setProfileId] = useState(props.suggestedProfileId);
|
|
263
|
+
const [selectedExistingProfileId, setSelectedExistingProfileId] = useState('');
|
|
264
|
+
const [submitting, setSubmitting] = useState(false);
|
|
265
|
+
const [status, setStatus] = useState(null);
|
|
266
|
+
const currentProfileId = selectedMode === 'overwrite' ? selectedExistingProfileId : profileId.trim();
|
|
267
|
+
const submitText = selectedMode === 'overwrite'
|
|
268
|
+
? tr('groups.saveProfileOverwriteSubmit')
|
|
269
|
+
: tr('groups.saveProfileSubmit');
|
|
270
|
+
const snapshotSummary = loadError
|
|
271
|
+
? loadError
|
|
272
|
+
: loadingSnapshot
|
|
273
|
+
? tr('groups.saveProfilePreparing')
|
|
274
|
+
: failedCount
|
|
275
|
+
? tr('groups.saveProfileFailedLoadSummary', { count: failedCount })
|
|
276
|
+
: entries.length
|
|
277
|
+
? emptyCount
|
|
278
|
+
? tr('groups.saveProfileEntrySummaryWithEmpty', { count: entries.length, emptyCount })
|
|
279
|
+
: tr('groups.saveProfileEntrySummary', { count: entries.length })
|
|
280
|
+
: tr('groups.saveProfileNoRoles');
|
|
281
|
+
useEffect(() => {
|
|
282
|
+
let alive = true;
|
|
283
|
+
setLoadingSnapshot(true);
|
|
284
|
+
setLoadError(null);
|
|
285
|
+
setStatus(null);
|
|
286
|
+
void (async () => {
|
|
287
|
+
try {
|
|
288
|
+
const [nextEntries, nextProfiles] = await Promise.all([
|
|
289
|
+
collectGroupProfileEntries(props.chat),
|
|
290
|
+
fetchRoleProfileSummaries().catch(() => []),
|
|
291
|
+
]);
|
|
292
|
+
if (!alive)
|
|
293
|
+
return;
|
|
294
|
+
const sortedNextProfiles = [...nextProfiles].sort((a, b) => a.profileId.localeCompare(b.profileId));
|
|
295
|
+
setEntries(nextEntries);
|
|
296
|
+
setProfiles(nextProfiles);
|
|
297
|
+
setSelectedExistingProfileId(cur => sortedNextProfiles.some(profile => profile.profileId === cur)
|
|
298
|
+
? cur
|
|
299
|
+
: sortedNextProfiles[0]?.profileId ?? '');
|
|
300
|
+
}
|
|
301
|
+
catch (err) {
|
|
302
|
+
if (!alive)
|
|
303
|
+
return;
|
|
304
|
+
setEntries([]);
|
|
305
|
+
setProfiles([]);
|
|
306
|
+
setSelectedExistingProfileId('');
|
|
307
|
+
setLoadError(err instanceof Error ? err.message : String(err));
|
|
308
|
+
}
|
|
309
|
+
finally {
|
|
310
|
+
if (alive)
|
|
311
|
+
setLoadingSnapshot(false);
|
|
312
|
+
}
|
|
313
|
+
})();
|
|
314
|
+
return () => { alive = false; };
|
|
315
|
+
}, [props.chat]);
|
|
316
|
+
async function submit(ev) {
|
|
317
|
+
ev.preventDefault();
|
|
318
|
+
if (!canSubmitSnapshot)
|
|
319
|
+
return;
|
|
320
|
+
if (!isValidProfileId(currentProfileId)) {
|
|
321
|
+
setStatus({ text: tr('groups.saveProfileInvalid'), className: 'error' });
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
setSubmitting(true);
|
|
325
|
+
setStatus({ text: tr('groups.saveProfileSaving') });
|
|
326
|
+
try {
|
|
327
|
+
const results = await Promise.all(entries.map(async (entry) => {
|
|
328
|
+
const r = await fetch(`/api/role-profiles/${encodeURIComponent(currentProfileId)}/${encodeURIComponent(entry.larkAppId)}`, {
|
|
329
|
+
method: 'PUT',
|
|
330
|
+
headers: { 'content-type': 'application/json' },
|
|
331
|
+
body: JSON.stringify({ content: entry.content, allowEmpty: true }),
|
|
332
|
+
});
|
|
333
|
+
return r.ok;
|
|
334
|
+
}));
|
|
335
|
+
const saved = results.filter(Boolean).length;
|
|
336
|
+
if (saved !== entries.length) {
|
|
337
|
+
setStatus({
|
|
338
|
+
text: tr('groups.saveProfileFailed', { saved, total: entries.length }),
|
|
339
|
+
className: 'error',
|
|
340
|
+
});
|
|
341
|
+
setSubmitting(false);
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
setStatus({
|
|
345
|
+
text: tr('groups.saveProfileDone', { name: currentProfileId, count: saved }),
|
|
346
|
+
className: 'ok',
|
|
347
|
+
});
|
|
348
|
+
await props.onRefreshRoleContext();
|
|
349
|
+
props.setTimer(props.onClose, 700);
|
|
350
|
+
}
|
|
351
|
+
catch (err) {
|
|
352
|
+
setStatus({ text: String(err), className: 'error' });
|
|
353
|
+
setSubmitting(false);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
function pickMode(mode) {
|
|
357
|
+
if (mode === 'overwrite' && !hasExistingProfiles)
|
|
358
|
+
return;
|
|
359
|
+
setSelectedMode(mode);
|
|
360
|
+
setStatus(null);
|
|
361
|
+
}
|
|
362
|
+
return (_jsxs("article", { className: "g-save-profile-dialog", children: [_jsxs("header", { children: [_jsx("h3", { children: tr('groups.saveProfileTitle') }), _jsx("p", { children: tr('groups.saveProfileIntro', {
|
|
363
|
+
name: props.chat.name ?? props.chat.chatId,
|
|
364
|
+
count: loadingSnapshot ? '-' : entries.length,
|
|
365
|
+
}) })] }), _jsxs("form", { id: "g-save-profile-form", onSubmit: ev => void submit(ev), children: [_jsxs("section", { className: "g-save-profile-panel", children: [_jsxs("div", { className: "g-save-profile-section-head", children: [_jsx("span", { children: tr('groups.saveProfileScope') }), _jsx("small", { children: tr('groups.saveProfileScopeHelp') })] }), _jsxs("div", { className: "g-save-profile-stats", children: [_jsxs("span", { children: [tr('groups.saveProfileBotCount'), " ", _jsx("strong", { children: loadingSnapshot ? '-' : entries.length })] }), failedCount ? _jsxs("span", { className: "warn", children: [tr('groups.saveProfileLoadFailed'), " ", _jsx("strong", { children: failedCount })] }) : null] }), _jsx("div", { className: "g-save-profile-entry-list", children: loadingSnapshot ? (_jsx("div", { className: "g-save-profile-loading", children: _jsx(LoadingState, { label: tr('common.loading') }) })) : loadError ? (_jsx("div", { className: "g-save-profile-empty", children: loadError })) : entries.length ? entries.map(entry => (_jsxs("div", { className: `g-save-profile-entry ${entry.status === 'error' ? 'error' : ''}`, children: [_jsxs("div", { children: [_jsx("strong", { children: entry.botName ?? entry.larkAppId }), _jsx("code", { children: entry.larkAppId })] }), _jsx("span", { className: `g-save-profile-entry-status ${entry.status === 'error' ? 'error' : 'ok'}`, children: tr(entry.status === 'error' ? 'groups.saveProfileStatus.error' : 'groups.saveProfileStatus.entry') })] }, entry.larkAppId))) : _jsx("div", { className: "g-save-profile-empty", children: tr('groups.saveProfileNoRoles') }) })] }), _jsxs("div", { className: "form-row", children: [_jsx("span", { children: tr('groups.saveProfileMode') }), _jsxs("div", { className: "g-save-profile-switch", role: "tablist", "aria-label": tr('groups.saveProfileMode'), children: [_jsx("button", { type: "button", className: selectedMode === 'new' ? 'active' : '', "data-save-profile-mode": "new", "aria-pressed": selectedMode === 'new', onClick: () => pickMode('new'), children: tr('groups.saveProfileNew') }), _jsx("button", { type: "button", className: selectedMode === 'overwrite' ? 'active' : '', "data-save-profile-mode": "overwrite", "aria-pressed": selectedMode === 'overwrite', disabled: !hasExistingProfiles, onClick: () => pickMode('overwrite'), children: tr('groups.saveProfileOverwrite') })] })] }), _jsxs("label", { className: "form-row", "data-profile-mode-row": "new", hidden: selectedMode !== 'new', children: [_jsx("span", { children: tr('groups.saveProfileIdLabel') }), _jsx("input", { type: "text", name: "profileId", value: profileId, maxLength: 64, autoComplete: "off", onChange: ev => {
|
|
366
|
+
setProfileId(ev.currentTarget.value);
|
|
367
|
+
setStatus(null);
|
|
368
|
+
} }), _jsx("small", { children: tr('groups.saveProfileInvalid') })] }), _jsxs("div", { className: "form-row", "data-profile-mode-row": "overwrite", hidden: selectedMode !== 'overwrite', children: [_jsx("span", { children: tr('groups.saveProfileExistingLabel') }), hasExistingProfiles ? (_jsx("div", { className: "g-save-profile-picker", children: sortedProfiles.map(profile => (_jsxs("button", { type: "button", className: `g-save-profile-pick ${profile.profileId === selectedExistingProfileId ? 'selected' : ''}`, "data-profile-id": profile.profileId, "aria-pressed": profile.profileId === selectedExistingProfileId, onClick: () => {
|
|
369
|
+
setSelectedExistingProfileId(profile.profileId);
|
|
370
|
+
setSelectedMode('overwrite');
|
|
371
|
+
setStatus(null);
|
|
372
|
+
}, children: [_jsx("span", { children: profile.profileId }), _jsx("small", { children: tr('groups.saveProfileExistingMeta', { count: profile.entryCount ?? 0 }) })] }, profile.profileId))) })) : _jsx("div", { className: "g-save-profile-summary warn", children: tr('groups.saveProfileExistingEmpty') }), _jsx("small", { children: tr('groups.saveProfileOverwriteHelp') })] }), _jsxs("div", { className: "g-save-profile-target", children: [_jsx("span", { children: tr('groups.saveProfileTarget') }), _jsx("code", { "data-save-profile-target": true, children: currentProfileId || '-' }), _jsx("small", { "data-save-profile-target-mode": true, children: selectedMode === 'overwrite' ? tr('groups.saveProfileTargetOverwrite') : tr('groups.saveProfileTargetNew') })] }), _jsx("div", { className: `g-save-profile-summary ${canSubmitSnapshot ? '' : 'warn'}`, children: snapshotSummary }), _jsx("div", { className: `g-save-profile-status ${status?.className ?? ''}`, "data-save-profile-status": true, children: status?.text ?? '' }), _jsxs("div", { className: "actions", children: [_jsx("button", { type: "button", id: "g-save-profile-cancel", onClick: props.onClose, children: tr('groups.cancel') }), _jsx("button", { type: "submit", className: "primary", disabled: !canSubmitSnapshot || submitting || (selectedMode === 'overwrite' && !selectedExistingProfileId), children: submitting ? tr('groups.saveProfileSaving') : submitText })] })] })] }));
|
|
373
|
+
}
|
|
374
|
+
function OncallRow(props) {
|
|
375
|
+
const { member, tr } = props;
|
|
376
|
+
const inputRef = useRef(null);
|
|
377
|
+
const [enabled, setEnabled] = useState(!!member.oncallChat);
|
|
378
|
+
const [workingDir, setWorkingDir] = useState(member.oncallChat?.workingDir ?? '');
|
|
379
|
+
const [saving, setSaving] = useState(false);
|
|
380
|
+
const [status, setStatus] = useState(null);
|
|
381
|
+
async function save() {
|
|
382
|
+
setStatus(null);
|
|
383
|
+
const wd = workingDir.trim();
|
|
384
|
+
if (enabled && !wd) {
|
|
385
|
+
setStatus({ text: tr('groups.needWorkingDir'), className: 'hint-warn-inline' });
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
setSaving(true);
|
|
389
|
+
try {
|
|
390
|
+
const url = `/api/groups/${encodeURIComponent(props.chat.chatId)}/oncall/${encodeURIComponent(member.larkAppId)}`;
|
|
391
|
+
const r = enabled
|
|
392
|
+
? await fetch(url, {
|
|
393
|
+
method: 'PUT',
|
|
394
|
+
headers: { 'content-type': 'application/json' },
|
|
395
|
+
body: JSON.stringify({ workingDir: wd }),
|
|
396
|
+
})
|
|
397
|
+
: await fetch(url, { method: 'DELETE' });
|
|
398
|
+
const body = await r.json().catch(() => ({}));
|
|
399
|
+
if (r.ok && body.ok) {
|
|
400
|
+
setStatus({
|
|
401
|
+
text: enabled ? `✓ 已绑定 → ${body.resolvedPath ?? wd}` : '✓ 已解绑',
|
|
402
|
+
className: 'hint-ok',
|
|
403
|
+
});
|
|
404
|
+
try {
|
|
405
|
+
await props.onSaved();
|
|
406
|
+
}
|
|
407
|
+
catch { /* tolerate */ }
|
|
408
|
+
}
|
|
409
|
+
else {
|
|
410
|
+
setStatus({ text: `✗ ${body.error ?? r.status}`, className: 'hint-warn-inline' });
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
catch (err) {
|
|
414
|
+
setStatus({ text: `✗ ${err?.message ?? err}`, className: 'hint-warn-inline' });
|
|
415
|
+
}
|
|
416
|
+
finally {
|
|
417
|
+
setSaving(false);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
return (_jsxs("div", { className: "oncall-row", "data-bot": member.larkAppId, children: [_jsxs("label", { className: "checkbox-row", children: [_jsx("input", { type: "checkbox", "data-action": "toggle", checked: enabled, onChange: ev => {
|
|
421
|
+
setEnabled(ev.currentTarget.checked);
|
|
422
|
+
if (ev.currentTarget.checked)
|
|
423
|
+
window.setTimeout(() => inputRef.current?.focus(), 0);
|
|
424
|
+
} }), _jsx("strong", { children: member.botName ?? member.larkAppId }), _jsxs("small", { children: ["(", member.larkAppId, ")"] })] }), _jsxs("div", { className: "oncall-row-body", children: [_jsx("input", { ref: inputRef, type: "text", "data-input": "workingDir", placeholder: "e.g. /root/iserver/botmux", value: workingDir, disabled: !enabled, onChange: ev => setWorkingDir(ev.currentTarget.value) }), _jsx("button", { type: "button", "data-action": "save", disabled: saving, onClick: () => void save(), children: tr('groups.save') }), _jsx("span", { className: `oncall-status ${status?.className ?? ''}`, "data-status": true, children: status?.text ?? '' })] })] }));
|
|
425
|
+
}
|
|
426
|
+
function ManageDialog(props) {
|
|
427
|
+
const { chat, tr } = props;
|
|
428
|
+
const inChat = (chat.memberBots ?? []).filter(member => member.inChat);
|
|
429
|
+
const ownerAppId = typeof chat.ownerId === 'string' ? chat.ownerId : '';
|
|
430
|
+
const [leaveSelection, setLeaveSelection] = useState(() => new Set());
|
|
431
|
+
function toggleLeave(appId, checked) {
|
|
432
|
+
setLeaveSelection(cur => {
|
|
433
|
+
const next = new Set(cur);
|
|
434
|
+
if (checked)
|
|
435
|
+
next.add(appId);
|
|
436
|
+
else
|
|
437
|
+
next.delete(appId);
|
|
438
|
+
return next;
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
async function leaveSelected() {
|
|
442
|
+
const checked = [...leaveSelection];
|
|
443
|
+
if (checked.length === 0) {
|
|
444
|
+
alert('至少选一个机器人');
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
if (!confirm(`确定让 ${checked.length} 个机器人退出群聊?该 bot 在此群的会话会一并关闭。`))
|
|
448
|
+
return;
|
|
449
|
+
try {
|
|
450
|
+
const r = await fetch(`/api/groups/${encodeURIComponent(chat.chatId)}/leave`, {
|
|
451
|
+
method: 'POST',
|
|
452
|
+
headers: { 'content-type': 'application/json' },
|
|
453
|
+
body: JSON.stringify({ larkAppIds: checked }),
|
|
454
|
+
});
|
|
455
|
+
const respBody = await r.json();
|
|
456
|
+
const lines = (respBody.result ?? []).map((x) => {
|
|
457
|
+
if (!x.ok)
|
|
458
|
+
return `${x.larkAppId}: 失败 (${x.error ?? 'unknown'})`;
|
|
459
|
+
const closed = (x.closedSessions ?? []);
|
|
460
|
+
const failed = closed.filter(c => !c.ok).length;
|
|
461
|
+
const ok = closed.length - failed;
|
|
462
|
+
const note = closed.length === 0
|
|
463
|
+
? ''
|
|
464
|
+
: failed === 0 ? `(关闭 ${ok} 个会话)` : `(关闭 ${ok} 个,${failed} 个失败)`;
|
|
465
|
+
return `${x.larkAppId}: OK${note}`;
|
|
466
|
+
}).join('\n');
|
|
467
|
+
alert(lines || `Unexpected: ${JSON.stringify(respBody)}`);
|
|
468
|
+
await props.onReloadGroups({ force: true });
|
|
469
|
+
}
|
|
470
|
+
catch (err) {
|
|
471
|
+
alert('Network error: ' + err);
|
|
472
|
+
}
|
|
473
|
+
finally {
|
|
474
|
+
props.onClose();
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
async function disband() {
|
|
478
|
+
if (inChat.length === 0)
|
|
479
|
+
return;
|
|
480
|
+
if (!confirm(`确定解散群聊「${chat.name ?? chat.chatId}」?此操作不可恢复,本群所有机器人会话也会一并关闭。`))
|
|
481
|
+
return;
|
|
482
|
+
const ordered = [...inChat].sort((a, b) => (b.larkAppId === ownerAppId ? 1 : 0) - (a.larkAppId === ownerAppId ? 1 : 0));
|
|
483
|
+
const errs = [];
|
|
484
|
+
for (const member of ordered) {
|
|
485
|
+
try {
|
|
486
|
+
const r = await fetch(`/api/groups/${encodeURIComponent(chat.chatId)}/disband`, {
|
|
487
|
+
method: 'POST',
|
|
488
|
+
headers: { 'content-type': 'application/json' },
|
|
489
|
+
body: JSON.stringify({ larkAppId: member.larkAppId }),
|
|
490
|
+
});
|
|
491
|
+
const respBody = await r.json();
|
|
492
|
+
if (respBody.ok) {
|
|
493
|
+
const closed = (respBody.closedSessions ?? []);
|
|
494
|
+
const failed = closed.filter(c => !c.ok).length;
|
|
495
|
+
const ok = closed.length - failed;
|
|
496
|
+
const closedNote = closed.length === 0
|
|
497
|
+
? ''
|
|
498
|
+
: failed === 0 ? `\n关闭了 ${ok} 个会话。` : `\n关闭了 ${ok} 个会话,${failed} 个会话关闭失败。`;
|
|
499
|
+
alert(`已解散(由 ${member.botName ?? member.larkAppId} 执行)${closedNote}`);
|
|
500
|
+
await props.onReloadGroups({ force: true });
|
|
501
|
+
props.onClose();
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
errs.push(`${member.botName ?? member.larkAppId}: ${respBody.error ?? r.status}`);
|
|
505
|
+
}
|
|
506
|
+
catch (err) {
|
|
507
|
+
errs.push(`${member.botName ?? member.larkAppId}: ${err}`);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
alert(`所有在群机器人均无法解散:\n${errs.join('\n')}\n\n建议改用「退出群聊」。`);
|
|
511
|
+
}
|
|
512
|
+
return (_jsxs("article", { className: "g-manage-dialog", children: [_jsx("header", { children: _jsx("h3", { children: tr('groups.manageTitle', { name: chat.name ?? chat.chatId }) }) }), _jsxs("div", { className: "g-manage-meta", children: [_jsxs("span", { children: [_jsx("b", { children: "chatId" }), _jsx("code", { children: chat.chatId })] }), _jsxs("span", { children: [_jsx("b", { children: tr('groups.owner') }), _jsx("code", { children: chat.ownerId ?? tr('common.unknown') })] })] }), _jsxs("fieldset", { children: [_jsx("legend", { children: tr('groups.oncall') }), _jsx("p", { children: _jsx("small", { children: tr('groups.oncallHelp') }) }), inChat.length === 0 ? (_jsx("p", { className: "empty", children: "\u6CA1\u6709\u673A\u5668\u4EBA\u5728\u7FA4\u91CC" })) : inChat.map(member => (_jsx(OncallRow, { chat: chat, member: member, tr: tr, onSaved: async () => { await props.onReloadGroups({ force: true }); } }, member.larkAppId)))] }), _jsxs("fieldset", { children: [_jsx("legend", { children: tr('groups.leaveTitle') }), inChat.length === 0 ? (_jsx("p", { className: "empty", children: "\u6CA1\u6709\u673A\u5668\u4EBA\u5728\u7FA4\u91CC" })) : (_jsx("div", { className: "g-leave-picker", children: inChat.map(member => (_jsxs("label", { className: "checkbox-row", children: [_jsx("input", { type: "checkbox", name: "leave-bot", value: member.larkAppId, checked: leaveSelection.has(member.larkAppId), onChange: ev => toggleLeave(member.larkAppId, ev.currentTarget.checked) }), _jsxs("span", { className: "checkbox-row-main", children: [_jsx("strong", { children: member.botName ?? member.larkAppId }), member.larkAppId === ownerAppId ? _jsx("small", { children: "\u00B7 \u7FA4\u4E3B" }) : null] })] }, member.larkAppId))) }))] }), _jsx("p", { className: "g-manage-danger-hint", children: tr('groups.dangerHint') }), _jsxs("div", { className: "actions", children: [_jsx("button", { type: "button", onClick: props.onClose, children: tr('sessions.dismiss') }), _jsx("button", { id: "g-leave-btn", type: "button", disabled: inChat.length === 0, onClick: () => void leaveSelected(), children: tr('groups.leaveSelected') }), _jsx("button", { id: "g-disband-btn", type: "button", className: "contrast", disabled: inChat.length === 0, onClick: () => void disband(), children: tr('groups.disband') })] })] }));
|
|
513
|
+
}
|
|
514
|
+
function DialogHost(props) {
|
|
515
|
+
const dialogRef = useRef(null);
|
|
516
|
+
useEffect(() => {
|
|
517
|
+
const dialog = dialogRef.current;
|
|
518
|
+
if (!dialog)
|
|
519
|
+
return undefined;
|
|
520
|
+
const onClose = () => props.onClose();
|
|
521
|
+
dialog.addEventListener('close', onClose);
|
|
522
|
+
return () => dialog.removeEventListener('close', onClose);
|
|
523
|
+
}, [props.onClose]);
|
|
524
|
+
useEffect(() => {
|
|
525
|
+
const dialog = dialogRef.current;
|
|
526
|
+
if (!dialog)
|
|
527
|
+
return;
|
|
528
|
+
if (props.dialog && !dialog.open)
|
|
529
|
+
dialog.showModal();
|
|
530
|
+
if (!props.dialog && dialog.open)
|
|
531
|
+
dialog.close();
|
|
532
|
+
}, [props.dialog]);
|
|
533
|
+
let content = null;
|
|
534
|
+
if (props.dialog?.type === 'create') {
|
|
535
|
+
content = (_jsx(CreateDialog, { bots: props.snapshot.bots, roleProfiles: props.dialog.roleProfiles, tr: props.tr, onClose: props.onClose, onCreated: props.onCreated, setTimer: props.setTimer }));
|
|
536
|
+
}
|
|
537
|
+
else if (props.dialog?.type === 'add-bots') {
|
|
538
|
+
content = (_jsx(AddBotsDialog, { chat: props.dialog.chat, bots: props.snapshot.bots, tr: props.tr, onClose: props.onClose, onReloadGroups: props.onReloadGroups }));
|
|
539
|
+
}
|
|
540
|
+
else if (props.dialog?.type === 'save-profile') {
|
|
541
|
+
content = (_jsx(SaveProfileDialog, { chat: props.dialog.chat, suggestedProfileId: props.dialog.suggestedProfileId, tr: props.tr, onClose: props.onClose, onRefreshRoleContext: props.onRefreshRoleContext, setTimer: props.setTimer }));
|
|
542
|
+
}
|
|
543
|
+
else if (props.dialog?.type === 'manage') {
|
|
544
|
+
content = (_jsx(ManageDialog, { chat: props.dialog.chat, tr: props.tr, onClose: props.onClose, onReloadGroups: props.onReloadGroups }));
|
|
545
|
+
}
|
|
546
|
+
const className = props.dialog?.type === 'create' ? 'groups-create-modal' : undefined;
|
|
547
|
+
return (_jsx("dialog", { id: "g-drawer", className: className, ref: dialogRef, onMouseDown: event => {
|
|
548
|
+
if (event.target === event.currentTarget)
|
|
549
|
+
event.currentTarget.close();
|
|
550
|
+
}, children: content }));
|
|
9
551
|
}
|
|
10
|
-
// Render-once scaffold: React owns the translated route shell, while
|
|
11
|
-
// wireGroupsPage owns the matrix and dialog flows until those controllers are
|
|
12
|
-
// split into reactive components. Keep ui-change rerenders as full remounts.
|
|
13
552
|
function GroupsPage() {
|
|
14
553
|
const tr = useT();
|
|
15
|
-
const
|
|
554
|
+
const mountedRef = useRef(false);
|
|
555
|
+
const snapshotRef = useRef(emptyGroupsSnapshot);
|
|
556
|
+
const timersRef = useRef(new Set());
|
|
557
|
+
const delayResolversRef = useRef(new Map());
|
|
558
|
+
const roleContextRunRef = useRef(0);
|
|
559
|
+
const [snapshot, setSnapshotState] = useState(emptyGroupsSnapshot);
|
|
560
|
+
const [roleContext, setRoleContext] = useState(() => emptyRoleContext());
|
|
561
|
+
const [filters, setFilters] = useState({ q: '', missingOnly: false });
|
|
562
|
+
const [loading, setLoading] = useState(true);
|
|
563
|
+
const [loadError, setLoadError] = useState(null);
|
|
564
|
+
const [refreshing, setRefreshing] = useState(false);
|
|
565
|
+
const [dialog, setDialog] = useState(null);
|
|
566
|
+
const [page, setPage] = useState(1);
|
|
567
|
+
const setSnapshot = useCallback((next) => {
|
|
568
|
+
setSnapshotState(cur => {
|
|
569
|
+
const resolved = typeof next === 'function' ? next(cur) : next;
|
|
570
|
+
snapshotRef.current = resolved;
|
|
571
|
+
return resolved;
|
|
572
|
+
});
|
|
573
|
+
}, []);
|
|
574
|
+
const setTimer = useCallback((fn, ms) => {
|
|
575
|
+
const id = window.setTimeout(() => {
|
|
576
|
+
timersRef.current.delete(id);
|
|
577
|
+
if (mountedRef.current)
|
|
578
|
+
fn();
|
|
579
|
+
}, ms);
|
|
580
|
+
timersRef.current.add(id);
|
|
581
|
+
return id;
|
|
582
|
+
}, []);
|
|
583
|
+
const delay = useCallback((ms) => new Promise(resolve => {
|
|
584
|
+
const id = window.setTimeout(() => {
|
|
585
|
+
timersRef.current.delete(id);
|
|
586
|
+
delayResolversRef.current.delete(id);
|
|
587
|
+
resolve();
|
|
588
|
+
}, ms);
|
|
589
|
+
timersRef.current.add(id);
|
|
590
|
+
delayResolversRef.current.set(id, resolve);
|
|
591
|
+
}), []);
|
|
592
|
+
const refreshRoleProfileContext = useCallback(async (source) => {
|
|
593
|
+
const runId = ++roleContextRunRef.current;
|
|
594
|
+
try {
|
|
595
|
+
const context = await loadGroupRoleProfileContext(source ?? snapshotRef.current);
|
|
596
|
+
if (mountedRef.current && runId === roleContextRunRef.current)
|
|
597
|
+
setRoleContext(context);
|
|
598
|
+
}
|
|
599
|
+
catch {
|
|
600
|
+
if (mountedRef.current && runId === roleContextRunRef.current) {
|
|
601
|
+
setRoleContext({ ...emptyRoleContext(), loaded: true });
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
}, []);
|
|
605
|
+
const reloadGroups = useCallback(async (options) => {
|
|
606
|
+
const next = await fetchGroupsSnapshot({ force: options?.force });
|
|
607
|
+
if (!mountedRef.current)
|
|
608
|
+
return next;
|
|
609
|
+
setSnapshot(next);
|
|
610
|
+
setLoadError(null);
|
|
611
|
+
void refreshRoleProfileContext(next);
|
|
612
|
+
return next;
|
|
613
|
+
}, [refreshRoleProfileContext, setSnapshot]);
|
|
614
|
+
const refreshUntilSeen = useCallback(async (chatId, expectedBotIds) => {
|
|
615
|
+
const delays = [600, 1200, 1200, 1200, 1200, 1200];
|
|
616
|
+
for (const ms of delays) {
|
|
617
|
+
await delay(ms);
|
|
618
|
+
if (!mountedRef.current)
|
|
619
|
+
return;
|
|
620
|
+
let next;
|
|
621
|
+
try {
|
|
622
|
+
next = await fetchGroupsSnapshot({ force: true });
|
|
623
|
+
}
|
|
624
|
+
catch {
|
|
625
|
+
continue;
|
|
626
|
+
}
|
|
627
|
+
if (!mountedRef.current)
|
|
628
|
+
return;
|
|
629
|
+
const row = (next.chats ?? []).find(chat => chat.chatId === chatId);
|
|
630
|
+
if (row && allExpectedInChat(row, expectedBotIds)) {
|
|
631
|
+
setSnapshot(next);
|
|
632
|
+
void refreshRoleProfileContext(next);
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
}, [delay, refreshRoleProfileContext, setSnapshot]);
|
|
16
637
|
useEffect(() => {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
638
|
+
mountedRef.current = true;
|
|
639
|
+
void (async () => {
|
|
640
|
+
setLoading(true);
|
|
641
|
+
try {
|
|
642
|
+
await reloadGroups();
|
|
643
|
+
}
|
|
644
|
+
catch (err) {
|
|
645
|
+
if (mountedRef.current) {
|
|
646
|
+
setSnapshot(emptyGroupsSnapshot);
|
|
647
|
+
setLoadError(err instanceof Error ? err.message : String(err));
|
|
648
|
+
void refreshRoleProfileContext(emptyGroupsSnapshot);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
finally {
|
|
652
|
+
if (mountedRef.current)
|
|
653
|
+
setLoading(false);
|
|
654
|
+
}
|
|
655
|
+
})();
|
|
656
|
+
return () => {
|
|
657
|
+
mountedRef.current = false;
|
|
658
|
+
roleContextRunRef.current += 1;
|
|
659
|
+
for (const id of timersRef.current)
|
|
660
|
+
window.clearTimeout(id);
|
|
661
|
+
timersRef.current.clear();
|
|
662
|
+
for (const resolve of delayResolversRef.current.values())
|
|
663
|
+
resolve();
|
|
664
|
+
delayResolversRef.current.clear();
|
|
665
|
+
};
|
|
666
|
+
}, [reloadGroups]);
|
|
667
|
+
const rows = useMemo(() => filterGroupChats(snapshot.chats, filters), [snapshot.chats, filters]);
|
|
668
|
+
const pageWindow = useMemo(() => paginateGroupRows(rows, page), [rows, page]);
|
|
669
|
+
useEffect(() => {
|
|
670
|
+
if (page !== pageWindow.page)
|
|
671
|
+
setPage(pageWindow.page);
|
|
672
|
+
}, [page, pageWindow.page]);
|
|
673
|
+
async function refresh() {
|
|
674
|
+
setRefreshing(true);
|
|
675
|
+
try {
|
|
676
|
+
await reloadGroups({ force: true });
|
|
677
|
+
}
|
|
678
|
+
catch (err) {
|
|
679
|
+
setLoadError(err instanceof Error ? err.message : String(err));
|
|
680
|
+
}
|
|
681
|
+
finally {
|
|
682
|
+
if (mountedRef.current)
|
|
683
|
+
setRefreshing(false);
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
async function openCreateDialog() {
|
|
687
|
+
if (snapshotRef.current.bots.length === 0) {
|
|
688
|
+
alert(tr('groups.noBotsOnline'));
|
|
689
|
+
return;
|
|
690
|
+
}
|
|
691
|
+
let roleProfiles = [];
|
|
692
|
+
try {
|
|
693
|
+
roleProfiles = await fetchRoleProfileSummaries();
|
|
694
|
+
}
|
|
695
|
+
catch { /* profile selector is optional */ }
|
|
696
|
+
if (mountedRef.current)
|
|
697
|
+
setDialog({ type: 'create', roleProfiles });
|
|
698
|
+
}
|
|
699
|
+
function handleCreated(resp, selectedIds, name) {
|
|
700
|
+
const chatId = String(resp.chatId);
|
|
701
|
+
const invalidBotIds = Array.isArray(resp.invalidBotIds) ? resp.invalidBotIds : [];
|
|
702
|
+
const validIds = selectedIds.filter(id => !invalidBotIds.includes(id));
|
|
703
|
+
const expectedBotIds = new Set(validIds);
|
|
704
|
+
if (typeof resp.creator === 'string' && resp.creator)
|
|
705
|
+
expectedBotIds.add(resp.creator);
|
|
706
|
+
// Compute the optimistic snapshot from committed state (setSnapshot keeps snapshotRef in
|
|
707
|
+
// sync) so the profile-context refresh always sees it — not a null from a deferred updater.
|
|
708
|
+
const optimistic = injectOptimisticChat(snapshotRef.current, chatId, name || chatId, validIds, resp.creator);
|
|
709
|
+
setSnapshot(optimistic);
|
|
710
|
+
void refreshRoleProfileContext(optimistic);
|
|
711
|
+
void refreshUntilSeen(chatId, expectedBotIds).catch(() => { });
|
|
712
|
+
}
|
|
713
|
+
const openAddBotsDialog = useCallback((chat) => {
|
|
714
|
+
const inChatSet = new Set((chat.memberBots ?? []).filter(member => member.inChat).map(member => member.larkAppId));
|
|
715
|
+
const missing = snapshotRef.current.bots.filter(bot => !inChatSet.has(bot.larkAppId));
|
|
716
|
+
if (!missing.length) {
|
|
717
|
+
alert('All configured bots are already in this chat.');
|
|
718
|
+
return;
|
|
719
|
+
}
|
|
720
|
+
setDialog({ type: 'add-bots', chat });
|
|
721
|
+
}, []);
|
|
722
|
+
const openSaveProfileDialog = useCallback((chat) => {
|
|
723
|
+
const suggestedByName = suggestRoleProfileIdFromChat(chat.name ?? '');
|
|
724
|
+
const suggestedProfileId = suggestedByName === 'profile'
|
|
725
|
+
? suggestRoleProfileIdFromChat(chat.chatId)
|
|
726
|
+
: suggestedByName;
|
|
727
|
+
setDialog({ type: 'save-profile', chat, suggestedProfileId });
|
|
728
|
+
}, []);
|
|
729
|
+
const openManageDialog = useCallback((chat) => {
|
|
730
|
+
setDialog({ type: 'manage', chat });
|
|
20
731
|
}, []);
|
|
21
|
-
|
|
732
|
+
function goToPage(nextPage) {
|
|
733
|
+
const list = document.getElementById('g-body');
|
|
734
|
+
if (list)
|
|
735
|
+
list.scrollTop = 0;
|
|
736
|
+
setPage(nextPage);
|
|
737
|
+
}
|
|
738
|
+
return (_jsxs("section", { className: "page groups-page", children: [_jsxs("div", { className: "page-heading", children: [_jsxs("div", { children: [_jsx("p", { className: "eyebrow", children: tr('nav.groups') }), _jsx("h1", { children: tr('groups.title') })] }), _jsx("div", { className: "page-heading-actions", children: _jsx(CreateActionButton, { id: "g-create", className: "page-primary-action", onClick: () => void openCreateDialog(), children: tr('groups.create') }) })] }), _jsxs("form", { id: "g-filters", className: "filters dashboard-toolbar groups-toolbar", onSubmit: ev => ev.preventDefault(), children: [_jsx("input", { type: "search", name: "q", placeholder: tr('groups.search'), value: filters.q, onChange: ev => {
|
|
739
|
+
const q = ev.currentTarget.value;
|
|
740
|
+
setPage(1);
|
|
741
|
+
setFilters(cur => ({ ...cur, q }));
|
|
742
|
+
} }), _jsxs("label", { className: "filter-toggle", children: [_jsx("input", { type: "checkbox", name: "missing", checked: filters.missingOnly, onChange: ev => {
|
|
743
|
+
const missingOnly = ev.currentTarget.checked;
|
|
744
|
+
setPage(1);
|
|
745
|
+
setFilters(cur => ({ ...cur, missingOnly }));
|
|
746
|
+
} }), _jsx("span", { className: "filter-toggle-label", children: tr('groups.missingOnly') }), _jsx("span", { className: "filter-toggle-switch", "aria-hidden": "true" })] }), _jsx("span", { className: "groups-toolbar-spacer", "aria-hidden": "true" }), _jsxs("span", { className: "groups-toolbar-count", children: [tr('groups.matrixTitle'), " ", loading ? '-/-' : `${rows.length}/${snapshot.chats.length}`] }), _jsx(RefreshIconButton, { id: "g-refresh", label: tr('groups.refresh'), busy: refreshing, disabled: refreshing, onClick: () => void refresh() })] }), loadError ? _jsxs("p", { className: "hint-warn", children: ["\u52A0\u8F7D\u7FA4\u7EC4\u5931\u8D25\uFF1A", loadError] }) : null, _jsx("section", { className: "overview-block groups-matrix-section", children: loading ? (_jsx("div", { id: "g-loading", children: _jsx(LoadingState, { label: tr('common.loading') }) })) : (_jsxs("div", { className: "groups-list-wrap", id: "g-table-wrap", children: [rows.length === 0 ? (_jsx("div", { className: "empty groups-list-empty", id: "g-body", children: tr('groups.empty') })) : (_jsx(OverviewList, { id: "g-body", className: "groups-list", children: pageWindow.rows.map(chat => (_jsx(GroupListRow, { chat: chat, bots: snapshot.bots, roleContext: roleContext, tr: tr, onAddBots: openAddBotsDialog, onSaveProfile: openSaveProfileDialog, onManage: openManageDialog }, chat.chatId))) })), rows.length > 0 && pageWindow.totalPages > 1 ? (_jsxs("nav", { className: "groups-pagination", "aria-label": tr('groups.paginationLabel'), children: [_jsx("span", { className: "groups-pagination-status", "aria-live": "polite", children: tr('groups.pageStatus', {
|
|
747
|
+
page: pageWindow.page,
|
|
748
|
+
pages: pageWindow.totalPages,
|
|
749
|
+
from: pageWindow.from,
|
|
750
|
+
to: pageWindow.to,
|
|
751
|
+
total: pageWindow.total,
|
|
752
|
+
}) }), _jsxs("div", { className: "groups-pagination-actions", children: [_jsx("button", { type: "button", disabled: pageWindow.page <= 1, onClick: () => goToPage(pageWindow.page - 1), children: tr('groups.prevPage') }), _jsx("button", { type: "button", disabled: pageWindow.page >= pageWindow.totalPages, onClick: () => goToPage(pageWindow.page + 1), children: tr('groups.nextPage') })] })] })) : null] })) }), _jsx(DialogHost, { dialog: dialog, snapshot: snapshot, tr: tr, onClose: () => setDialog(null), onCreated: handleCreated, onReloadGroups: reloadGroups, onRefreshRoleContext: () => refreshRoleProfileContext(), setTimer: setTimer })] }));
|
|
22
753
|
}
|
|
23
754
|
export function renderGroupsPage(root) {
|
|
24
755
|
return mountReactPage(root, _jsx(GroupsPage, {}));
|