@acorex/modules 21.0.0-next.55 → 21.0.0-next.57

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.
Files changed (70) hide show
  1. package/fesm2022/acorex-modules-ai-management.mjs.map +1 -1
  2. package/fesm2022/acorex-modules-application-management.mjs +1 -1
  3. package/fesm2022/acorex-modules-application-management.mjs.map +1 -1
  4. package/fesm2022/{acorex-modules-auth-acorex-modules-auth-NPUjHz-F.mjs → acorex-modules-auth-acorex-modules-auth-wfCSNwXC.mjs} +14 -14
  5. package/fesm2022/{acorex-modules-auth-acorex-modules-auth-NPUjHz-F.mjs.map → acorex-modules-auth-acorex-modules-auth-wfCSNwXC.mjs.map} +1 -1
  6. package/fesm2022/{acorex-modules-auth-app-chooser.component-h61xNtRT.mjs → acorex-modules-auth-app-chooser.component-BY281-Cl.mjs} +2 -2
  7. package/fesm2022/{acorex-modules-auth-app-chooser.component-h61xNtRT.mjs.map → acorex-modules-auth-app-chooser.component-BY281-Cl.mjs.map} +1 -1
  8. package/fesm2022/{acorex-modules-auth-login.module-DF5AHqYe.mjs → acorex-modules-auth-login.module-CjgYlyOv.mjs} +4 -4
  9. package/fesm2022/{acorex-modules-auth-login.module-DF5AHqYe.mjs.map → acorex-modules-auth-login.module-CjgYlyOv.mjs.map} +1 -1
  10. package/fesm2022/{acorex-modules-auth-master.layout-00ZTMhc3.mjs → acorex-modules-auth-master.layout-Clx8QDYW.mjs} +2 -2
  11. package/fesm2022/{acorex-modules-auth-master.layout-00ZTMhc3.mjs.map → acorex-modules-auth-master.layout-Clx8QDYW.mjs.map} +1 -1
  12. package/fesm2022/{acorex-modules-auth-oauth-callback.component-Ce5Fw8Qd.mjs → acorex-modules-auth-oauth-callback.component-CGnGAPJ2.mjs} +2 -2
  13. package/fesm2022/{acorex-modules-auth-oauth-callback.component-Ce5Fw8Qd.mjs.map → acorex-modules-auth-oauth-callback.component-CGnGAPJ2.mjs.map} +1 -1
  14. package/fesm2022/{acorex-modules-auth-password.component-DQYCm8wg.mjs → acorex-modules-auth-password.component-8eEX0lRP.mjs} +2 -2
  15. package/fesm2022/{acorex-modules-auth-password.component-DQYCm8wg.mjs.map → acorex-modules-auth-password.component-8eEX0lRP.mjs.map} +1 -1
  16. package/fesm2022/{acorex-modules-auth-password.component-CU0AY-Ia.mjs → acorex-modules-auth-password.component-CUxwThnN.mjs} +2 -2
  17. package/fesm2022/{acorex-modules-auth-password.component-CU0AY-Ia.mjs.map → acorex-modules-auth-password.component-CUxwThnN.mjs.map} +1 -1
  18. package/fesm2022/{acorex-modules-auth-routes-CM4fRaWb.mjs → acorex-modules-auth-routes-CYLKJm9g.mjs} +2 -2
  19. package/fesm2022/{acorex-modules-auth-routes-CM4fRaWb.mjs.map → acorex-modules-auth-routes-CYLKJm9g.mjs.map} +1 -1
  20. package/fesm2022/{acorex-modules-auth-tenant-chooser.component-BBztdcvq.mjs → acorex-modules-auth-tenant-chooser.component-DDK1KW-8.mjs} +2 -2
  21. package/fesm2022/{acorex-modules-auth-tenant-chooser.component-BBztdcvq.mjs.map → acorex-modules-auth-tenant-chooser.component-DDK1KW-8.mjs.map} +1 -1
  22. package/fesm2022/{acorex-modules-auth-two-factor.module-C9AafF86.mjs → acorex-modules-auth-two-factor.module-Iw2U7Cy5.mjs} +2 -2
  23. package/fesm2022/{acorex-modules-auth-two-factor.module-C9AafF86.mjs.map → acorex-modules-auth-two-factor.module-Iw2U7Cy5.mjs.map} +1 -1
  24. package/fesm2022/{acorex-modules-auth-user-sessions.component-Qw2sgsEe.mjs → acorex-modules-auth-user-sessions.component-sKDANprs.mjs} +2 -2
  25. package/fesm2022/{acorex-modules-auth-user-sessions.component-Qw2sgsEe.mjs.map → acorex-modules-auth-user-sessions.component-sKDANprs.mjs.map} +1 -1
  26. package/fesm2022/acorex-modules-auth.mjs +1 -1
  27. package/fesm2022/{acorex-modules-common-audit-info-column.component-SiqKcBMQ.mjs → acorex-modules-common-audit-info-column.component-MSYPMPZJ.mjs} +2 -2
  28. package/fesm2022/{acorex-modules-common-audit-info-column.component-SiqKcBMQ.mjs.map → acorex-modules-common-audit-info-column.component-MSYPMPZJ.mjs.map} +1 -1
  29. package/fesm2022/acorex-modules-common.mjs +1 -1
  30. package/fesm2022/{acorex-modules-conversation-acorex-modules-conversation-UNhA-qi5.mjs → acorex-modules-conversation-acorex-modules-conversation-DlteA_jC.mjs} +343 -1008
  31. package/fesm2022/acorex-modules-conversation-acorex-modules-conversation-DlteA_jC.mjs.map +1 -0
  32. package/fesm2022/{acorex-modules-conversation-assist-delegated-agent-detail-popup.component-Be58gcns.mjs → acorex-modules-conversation-assist-delegated-agent-detail-popup.component-BAgBuxlz.mjs} +2 -2
  33. package/fesm2022/{acorex-modules-conversation-assist-delegated-agent-detail-popup.component-Be58gcns.mjs.map → acorex-modules-conversation-assist-delegated-agent-detail-popup.component-BAgBuxlz.mjs.map} +1 -1
  34. package/fesm2022/{acorex-modules-conversation-comments-page.component-3XBLeMW8.mjs → acorex-modules-conversation-comments-page.component-BrwP9l7M.mjs} +2 -2
  35. package/fesm2022/{acorex-modules-conversation-comments-page.component-3XBLeMW8.mjs.map → acorex-modules-conversation-comments-page.component-BrwP9l7M.mjs.map} +1 -1
  36. package/fesm2022/{acorex-modules-conversation-send-assist-chat-message.command-CSu-lJuu.mjs → acorex-modules-conversation-send-assist-chat-message.command-BzKawEoN.mjs} +2 -2
  37. package/fesm2022/{acorex-modules-conversation-send-assist-chat-message.command-CSu-lJuu.mjs.map → acorex-modules-conversation-send-assist-chat-message.command-BzKawEoN.mjs.map} +1 -1
  38. package/fesm2022/{acorex-modules-conversation-start-assist-chat.command-CyoncQB1.mjs → acorex-modules-conversation-start-assist-chat.command-BUOGUMl0.mjs} +2 -2
  39. package/fesm2022/{acorex-modules-conversation-start-assist-chat.command-CyoncQB1.mjs.map → acorex-modules-conversation-start-assist-chat.command-BUOGUMl0.mjs.map} +1 -1
  40. package/fesm2022/acorex-modules-conversation.mjs +1 -1
  41. package/fesm2022/acorex-modules-locale-management.mjs +27 -22
  42. package/fesm2022/acorex-modules-locale-management.mjs.map +1 -1
  43. package/fesm2022/acorex-modules-notification-management.mjs +1 -1
  44. package/fesm2022/acorex-modules-notification-management.mjs.map +1 -1
  45. package/fesm2022/acorex-modules-platform-dev-tools.mjs +2 -2
  46. package/fesm2022/acorex-modules-platform-dev-tools.mjs.map +1 -1
  47. package/fesm2022/acorex-modules-report-management.mjs +1 -1
  48. package/fesm2022/acorex-modules-report-management.mjs.map +1 -1
  49. package/fesm2022/{acorex-modules-settings-management-acorex-modules-settings-management-Di6Sxtq3.mjs → acorex-modules-settings-management-acorex-modules-settings-management-B4Ee8USF.mjs} +6 -6
  50. package/fesm2022/{acorex-modules-settings-management-acorex-modules-settings-management-Di6Sxtq3.mjs.map → acorex-modules-settings-management-acorex-modules-settings-management-B4Ee8USF.mjs.map} +1 -1
  51. package/fesm2022/{acorex-modules-settings-management-permission-definition.provider-Bml5VZUT.mjs → acorex-modules-settings-management-permission-definition.provider-nNhEFyc-.mjs} +2 -2
  52. package/fesm2022/{acorex-modules-settings-management-permission-definition.provider-Bml5VZUT.mjs.map → acorex-modules-settings-management-permission-definition.provider-nNhEFyc-.mjs.map} +1 -1
  53. package/fesm2022/{acorex-modules-settings-management-setting-page.component-lN-7sTpD.mjs → acorex-modules-settings-management-setting-page.component-CEvWwS_a.mjs} +2 -2
  54. package/fesm2022/{acorex-modules-settings-management-setting-page.component-lN-7sTpD.mjs.map → acorex-modules-settings-management-setting-page.component-CEvWwS_a.mjs.map} +1 -1
  55. package/fesm2022/{acorex-modules-settings-management-setting-view.component-D17G4RNQ.mjs → acorex-modules-settings-management-setting-view.component-C6ftmjuK.mjs} +2 -2
  56. package/fesm2022/{acorex-modules-settings-management-setting-view.component-D17G4RNQ.mjs.map → acorex-modules-settings-management-setting-view.component-C6ftmjuK.mjs.map} +1 -1
  57. package/fesm2022/acorex-modules-settings-management.mjs +1 -1
  58. package/fesm2022/{acorex-modules-task-management-acorex-modules-task-management-LQn5gZ6p.mjs → acorex-modules-task-management-acorex-modules-task-management-CrybKNgo.mjs} +2 -2
  59. package/fesm2022/{acorex-modules-task-management-acorex-modules-task-management-LQn5gZ6p.mjs.map → acorex-modules-task-management-acorex-modules-task-management-CrybKNgo.mjs.map} +1 -1
  60. package/fesm2022/{acorex-modules-task-management-task-board.page-BokG-G6Z.mjs → acorex-modules-task-management-task-board.page-B2xxXscG.mjs} +4 -4
  61. package/fesm2022/{acorex-modules-task-management-task-board.page-BokG-G6Z.mjs.map → acorex-modules-task-management-task-board.page-B2xxXscG.mjs.map} +1 -1
  62. package/fesm2022/acorex-modules-task-management.mjs +1 -1
  63. package/fesm2022/{acorex-modules-workflow-management-index-BxqOP8AA.mjs → acorex-modules-workflow-management-index-RRzkvrNM.mjs} +102 -21
  64. package/fesm2022/acorex-modules-workflow-management-index-RRzkvrNM.mjs.map +1 -0
  65. package/fesm2022/acorex-modules-workflow-management.mjs +2 -2
  66. package/package.json +2 -2
  67. package/types/acorex-modules-ai-management.d.ts +4 -0
  68. package/types/acorex-modules-conversation.d.ts +35 -198
  69. package/fesm2022/acorex-modules-conversation-acorex-modules-conversation-UNhA-qi5.mjs.map +0 -1
  70. package/fesm2022/acorex-modules-workflow-management-index-BxqOP8AA.mjs.map +0 -1
@@ -1,29 +1,26 @@
1
1
  import { AXConversationModule } from '@acorex/components/conversation';
2
2
  import { AXPSessionService, AXPAuthGuard, AXP_PERMISSION_DEFINITION_PROVIDER } from '@acorex/platform/auth';
3
3
  import { createAllQueryView, AXPEntityQueryType, AXPSettingsService, AXPCommonSettings, AXPFilterOperatorMiddlewareService, AXPEntityCommandScope, AXPFileStorageService, AXP_MENU_PROVIDER, AXP_SEARCH_PROVIDER, AXP_SEARCH_DEFINITION_PROVIDER } from '@acorex/platform/common';
4
- import { AXPSystemActionType, AXPDataGenerator, AXPPlatformScope, AXPDeviceService, AXP_MODULE_MANIFEST_PROVIDER } from '@acorex/platform/core';
4
+ import { AXPSystemActionType, AXPPlatformScope, AXPDeviceService, AXP_MODULE_MANIFEST_PROVIDER } from '@acorex/platform/core';
5
5
  import { AXPMarkdownViewerComponent, AXPThemeLayoutBlockComponent, AXPThemeLayoutStartSideComponent, AXPUserAvatarComponent, AXPMarkdownTemplateDirective, AXP_PAGE_COMPONENT_PROVIDER, AXP_TASK_BADGE_PROVIDERS } from '@acorex/platform/layout/components';
6
- import { AXPEntityDefinitionRegistryService, AXMEntityCrudServiceImpl, entityMasterCrudActions, entityMasterRecordActions, AXPEntityService, cloneLayoutArrays, ensureLayoutSection, ensureLayoutPropertyView, resolveEntityPluginDetailPageOrder, ensureListActions, actionExists, AXP_ENTITY_ACTION_PLUGIN, AXP_ENTITY_DEFINITION_LOADER } from '@acorex/platform/layout/entity';
6
+ import { AXMEntityCrudServiceImpl, entityMasterCrudActions, entityMasterRecordActions, AXPEntityDefinitionRegistryService, AXPEntityService, cloneLayoutArrays, ensureLayoutSection, ensureLayoutPropertyView, resolveEntityPluginDetailPageOrder, ensureListActions, actionExists, AXP_ENTITY_ACTION_PLUGIN, AXP_ENTITY_DEFINITION_LOADER } from '@acorex/platform/layout/entity';
7
+ import { AXPCommandService, provideCommandSetups } from '@acorex/platform/runtime';
7
8
  import { AXPRootLayoutComponent } from '@acorex/platform/themes/default';
8
9
  import * as i5 from '@angular/common';
9
10
  import { AsyncPipe, CommonModule, isPlatformBrowser, DecimalPipe, DatePipe } from '@angular/common';
10
- import { AXPCommandService, provideCommandSetups } from '@acorex/platform/runtime';
11
11
  import * as i0 from '@angular/core';
12
- import { inject, Injectable, NgModule, input, computed, ChangeDetectionStrategy, Component, signal, effect, untracked, output, viewChild, afterNextRender, DestroyRef, ElementRef, ViewEncapsulation, PLATFORM_ID, Injector, importProvidersFrom } from '@angular/core';
12
+ import { Injectable, NgModule, inject, computed, input, ChangeDetectionStrategy, Component, signal, effect, untracked, output, viewChild, afterNextRender, DestroyRef, ElementRef, ViewEncapsulation, PLATFORM_ID, Injector, importProvidersFrom } from '@angular/core';
13
13
  import { Router, ActivatedRoute, RouterModule, ROUTES } from '@angular/router';
14
+ import * as i1$2 from '@acorex/platform/layout/widget-core';
15
+ import { AXPWidgetsCatalog, AXPValueWidgetComponent, AXPWidgetGroupEnum, AXPWidgetCoreModule, AXP_WIDGET_DEFINITION_PROVIDER } from '@acorex/platform/layout/widget-core';
14
16
  import { sortBy } from 'lodash-es';
15
17
  import { RootConfig as RootConfig$1, axpAiAssistStarterPromptLabels, axpAiAssistInitialMessagesToTranscript, axpAiChatMessageGetText, AXPAiManagerService, axpAiChatMessageIsDelegatedReflectionExcluded, axpAiDelegatedAgentResultSegments, axpAiChatTextMessage, AXPAiChatToolRunContextService, AXPAiPlatformRuntimeContextBuilder, AIMANAGEMENT_STRUCTURED_TEXT_COMPLETION_COMMAND_KEY, persistAiChatAttachmentImage, AIMANAGEMENT_CHAT_TRANSCRIBE_SPEECH_COMMAND_KEY, AXPAiAssistChatModelCatalogService, axpAiParseSupervisorAgentToolName, axpAiDelegatedAgentPromptPreview, axpAiChatToolOrAgentResultBodyJson, axpAiDelegatedAgentOutcomeResponsesPlainText } from '@acorex/modules/ai-management';
16
18
  import { AXConversationService, AXUserApi, AXConversationApi, AXMessageApi, AXRealtimeApi, conversationSharedStorage, AXNewConversationDialogComponent, AXComposerService, AXInfoBarService, AXConversationContainerDirective, AXSidebarComponent, AXInfoBarComponent, AXMessageListComponent, AXComposerComponent, axConversationIndexedDbStorage, AXImageRendererComponent, AXTextRendererComponent, provideConversation, AX_CONVERSATION_ITEM_MUTE_ACTION, AX_CONVERSATION_ITEM_PIN_ACTION, AX_CONVERSATION_ITEM_MARK_READ_ACTION, AX_CONVERSATION_ITEM_DIVIDER, AX_CONVERSATION_ITEM_DELETE_ACTION, AX_CONVERSATION_ITEM_BLOCK_ACTION, AX_CONVERSATION_INFO_BAR_SEARCH_ACTION, AX_CONVERSATION_INFO_BAR_INFO_ACTION, AX_CONVERSATION_INFO_BAR_MUTE_ACTION, AX_CONVERSATION_INFO_BAR_DIVIDER, AX_CONVERSATION_INFO_BAR_DELETE_ACTION, AX_CONVERSATION_INFO_BAR_BLOCK_ACTION, AX_CONVERSATION_TAB_ALL, AX_CONVERSATION_TAB_PRIVATE, AX_CONVERSATION_TAB_GROUPS, AX_CONVERSATION_COMPOSER_EMOJI_TAB, AX_CONVERSATION_COMPOSER_STICKER_TAB, AX_CONVERSATION_COMPOSER_EMOJI_ACTION, AX_CONVERSATION_COMPOSER_IMAGE_ACTION, AX_CONVERSATION_COMPOSER_VIDEO_ACTION, AX_CONVERSATION_COMPOSER_FILE_ACTION, AX_CONVERSATION_COMPOSER_AUDIO_ACTION, AX_CONVERSATION_COMPOSER_LOCATION_ACTION, AX_CONVERSATION_MESSAGE_REPLY_ACTION, AX_CONVERSATION_MESSAGE_FORWARD_ACTION, AX_CONVERSATION_MESSAGE_EDIT_ACTION, AX_CONVERSATION_MESSAGE_DELETE_ACTION, AX_CONVERSATION_TEXT_RENDERER, AX_CONVERSATION_IMAGE_RENDERER, AX_CONVERSATION_VIDEO_RENDERER, AX_CONVERSATION_AUDIO_RENDERER, AX_CONVERSATION_VOICE_RENDERER, AX_CONVERSATION_FILE_RENDERER, AX_CONVERSATION_LOCATION_RENDERER, AX_CONVERSATION_STICKER_RENDERER } from '@acorex/components/conversation2';
17
19
  import { AXToastService } from '@acorex/components/toast';
18
20
  import * as i3 from '@acorex/core/translation';
19
21
  import { AXTranslationService, AXTranslationModule } from '@acorex/core/translation';
20
- import * as i1$2 from '@acorex/platform/layout/widget-core';
21
- import { AXPWidgetsCatalog, AXPValueWidgetComponent, AXPWidgetGroupEnum, AXPWidgetCoreModule, AXP_WIDGET_DEFINITION_PROVIDER } from '@acorex/platform/layout/widget-core';
22
22
  import * as i1$5 from '@acorex/platform/workflow';
23
23
  import { AXPWorkflowAction, AXPWorkflowModule } from '@acorex/platform/workflow';
24
- import { AXMNotificationConnectorService, AXP_NOTIFICATION_DEFINITION_PROVIDER } from '@acorex/modules/notification-management';
25
- import { AXMUsersEntityService } from '@acorex/modules/security-management';
26
- import { Subject, map, filter, merge, auditTime } from 'rxjs';
27
24
  import * as i2 from '@acorex/components/button';
28
25
  import { AXButtonModule, AXButtonComponent } from '@acorex/components/button';
29
26
  import * as i2$1 from '@acorex/components/decorators';
@@ -31,6 +28,7 @@ import { AXDecoratorModule } from '@acorex/components/decorators';
31
28
  import { AXDialogService } from '@acorex/components/dialog';
32
29
  import { AXPPageLayoutBaseComponent, AXPPageLayoutComponent } from '@acorex/platform/layout/views';
33
30
  import { toSignal, takeUntilDestroyed } from '@angular/core/rxjs-interop';
31
+ import { map, Subject, filter } from 'rxjs';
34
32
  import * as i3$1 from '@acorex/components/dropdown';
35
33
  import { AXDropdownModule } from '@acorex/components/dropdown';
36
34
  import { AXTextBoxModule } from '@acorex/components/text-box';
@@ -44,6 +42,7 @@ import { AXImageComponent, AXImageModule } from '@acorex/components/image';
44
42
  import { AXListComponent } from '@acorex/components/list';
45
43
  import { AXBasePageComponent } from '@acorex/components/page';
46
44
  import { AXSearchBoxComponent } from '@acorex/components/search-box';
45
+ import { AXMUsersEntityService } from '@acorex/modules/security-management';
47
46
  import * as i1$1 from '@acorex/components/wysiwyg';
48
47
  import { AXWysiwygModule } from '@acorex/components/wysiwyg';
49
48
  import { trigger, transition, style, animate } from '@angular/animations';
@@ -59,6 +58,7 @@ import { AXSkeletonModule } from '@acorex/components/skeleton';
59
58
  import { AXToolBarModule } from '@acorex/components/toolbar';
60
59
  import * as i9 from '@acorex/core/format';
61
60
  import { AXFormatModule } from '@acorex/core/format';
61
+ import { AXMNotificationConnectorService, AXP_NOTIFICATION_DEFINITION_PROVIDER } from '@acorex/modules/notification-management';
62
62
  import { AXPLayoutBuilderService, AXPLayoutRendererComponent } from '@acorex/platform/layout/builder';
63
63
  import { AXLabelModule } from '@acorex/components/label';
64
64
  import * as i1$4 from '@acorex/cdk/accordion';
@@ -101,283 +101,18 @@ const RootConfig = {
101
101
  },
102
102
  };
103
103
 
104
- /** Starts a new bot conversation with the given AI assist model. */
105
- const CONVERSATION_START_ASSIST_CHAT_COMMAND = 'Conversation:StartAssistChat';
106
- /** Sends a user text message in the active assist chat, or starts a chat when {@code assistId} is provided. */
107
- const CONVERSATION_SEND_ASSIST_CHAT_MESSAGE_COMMAND = 'Conversation:SendAssistChatMessage';
108
-
109
- //#region ---- Imports ----
110
- //#endregion
111
- //#region ---- Participant & metadata ----
112
- /** Synthetic bot participant id for assist chats. */
113
- function axmChatAiPeerParticipantId(catalogId) {
114
- return `assist-${catalogId.trim()}`;
115
- }
116
- /** Conversation metadata for starting an AI chat from a picker row. */
117
- function axmBuildAiChatConversationMetadata(row) {
118
- return { assistId: row.id };
119
- }
120
- /** True when conversation metadata targets an assist row. */
121
- function axmConversationHasAiChat(conversation) {
122
- const assistId = conversation?.metadata?.['assistId'];
123
- return typeof assistId === 'string' && assistId.trim().length > 0;
124
- }
125
- /** Loads assist rows for Conversation AI chat pickers. */
126
- async function axmLoadChatAiTargets(entityRegistry) {
127
- const assists = await axmQueryEntityList(entityRegistry, RootConfig$1.entities.assist.name);
128
- return assists
129
- .map((raw) => ({
130
- id: String(raw['id'] ?? ''),
131
- name: String(raw['name'] ?? ''),
132
- title: raw['title'],
133
- description: raw['description'],
134
- professionImageUrl: typeof raw['professionImageUrl'] === 'string' ? raw['professionImageUrl'] : undefined,
135
- }))
136
- .filter((row) => row.id.trim().length > 0)
137
- .sort((a, b) => a.name.localeCompare(b.name, undefined, { sensitivity: 'base' }));
138
- }
139
- //#endregion
140
- //#region ---- Display & filter (dialog + global search) ----
141
- /** Resolves ML or plain string for search/display. */
142
- function axmResolveChatAiTargetText(resolveMl, value) {
143
- if (!value) {
144
- return '';
145
- }
146
- if (typeof value === 'string') {
147
- return value;
148
- }
149
- return resolveMl(value) ?? '';
150
- }
151
- function axmChatAiTargetDisplayName(resolveMl, row) {
152
- return axmResolveChatAiTargetText(resolveMl, row.title).trim() || row.name.trim() || row.id;
153
- }
154
- function axmChatAiTargetDisplayDescription(resolveMl, row) {
155
- if (!row.description) {
156
- return undefined;
157
- }
158
- const text = axmResolveChatAiTargetText(resolveMl, row.description).trim();
159
- return text || undefined;
160
- }
161
- function axmChatAiTargetAvatarUrl(row) {
162
- const url = row.professionImageUrl?.trim();
163
- return url ? url : null;
164
- }
165
- /** Fallback i18n key for rows with no catalog description. */
166
- function axmChatAiTargetShortcutDescriptionKey() {
167
- return '@conversation:search.assist.shortcut-description';
168
- }
169
- /** Same filter as {@link AXMChatWithAssistDialogComponent} target list search. */
170
- function axmFilterChatAiTargets(resolveMl, rows, query) {
171
- const q = query.trim().toLowerCase();
172
- if (!q) {
173
- return rows;
174
- }
175
- return rows.filter((r) => {
176
- const titleText = axmResolveChatAiTargetText(resolveMl, r.title).toLowerCase();
177
- return (r.name.toLowerCase().includes(q) ||
178
- titleText.includes(q) ||
179
- axmResolveChatAiTargetText(resolveMl, r.description).toLowerCase().includes(q));
180
- });
181
- }
182
- //#endregion
183
- //#region ---- Entity list query ----
184
- async function axmQueryEntityList(entityRegistry, entityName) {
185
- const entity = await entityRegistry.resolve(RootConfig$1.module.name, entityName);
186
- const execute = entity.queries?.list?.execute;
187
- if (!execute) {
188
- throw new Error(`${entityName} entity has no list query.`);
189
- }
190
- const res = await execute({
191
- skip: 0,
192
- take: 500,
193
- sort: [{ name: 'name', dir: 'asc' }],
194
- });
195
- return res.items ?? [];
196
- }
197
- //#endregion
198
-
199
- //#region ---- Imports ----
200
- //#endregion
201
- //#region ---- Service ----
202
- /**
203
- * Starts bot conversations from catalog assist rows,
204
- * shared by global search shortcuts and {@link AXMConversationStartAssistChatCommand}.
205
- */
206
- class AXMChatAssistLauncherService {
207
- constructor() {
208
- this.conversationService = inject(AXConversationService);
209
- this.entityRegistry = inject(AXPEntityDefinitionRegistryService);
210
- this.translationService = inject(AXTranslationService);
211
- this.sessionService = inject(AXPSessionService);
212
- this.router = inject(Router);
213
- this.toastService = inject(AXToastService);
214
- this.targetsCache = null;
215
- this.loadPromise = null;
216
- }
217
- async loadTargets(force = false) {
218
- if (!force && this.targetsCache) {
219
- return this.targetsCache;
220
- }
221
- if (!force && this.loadPromise) {
222
- return this.loadPromise;
223
- }
224
- this.loadPromise = axmLoadChatAiTargets(this.entityRegistry);
225
- try {
226
- this.targetsCache = await this.loadPromise;
227
- return this.targetsCache;
228
- }
229
- finally {
230
- this.loadPromise = null;
231
- }
232
- }
233
- displayName(row) {
234
- return axmChatAiTargetDisplayName(this.#resolveMl.bind(this), row);
235
- }
236
- displayDescription(row) {
237
- return axmChatAiTargetDisplayDescription(this.#resolveMl.bind(this), row);
238
- }
239
- targetAvatarUrl(row) {
240
- return axmChatAiTargetAvatarUrl(row);
241
- }
242
- filterTargets(rows, query) {
243
- return axmFilterChatAiTargets(this.#resolveMl.bind(this), rows, query);
244
- }
245
- async startAssistChat(options) {
246
- const targetId = (options.targetId ?? options.assistId)?.trim();
247
- if (!targetId) {
248
- return null;
249
- }
250
- const rows = await this.loadTargets();
251
- const row = rows.find((r) => r.id === targetId);
252
- if (!row) {
253
- const message = await this.translationService.translateAsync('@conversation:chat.assist-dialog.errors.start-chat');
254
- this.toastService.danger(message);
255
- return null;
256
- }
257
- try {
258
- const conversation = await this.#createTargetConversation(row);
259
- await this.conversationService.selectConversation(conversation.id);
260
- if (options.navigate !== false) {
261
- await this.router.navigate([this.#applicationRouteSegment(), 'chat', conversation.id]);
262
- }
263
- return { conversation };
264
- }
265
- catch (error) {
266
- console.error('Failed to start AI chat:', error);
267
- const message = await this.translationService.translateAsync('@conversation:chat.assist-dialog.errors.start-chat');
268
- this.toastService.danger(message);
269
- return null;
270
- }
271
- }
272
- async #createTargetConversation(row) {
273
- const participantId = axmChatAiPeerParticipantId(row.id);
274
- const title = this.displayName(row);
275
- const avatar = this.targetAvatarUrl(row);
276
- return this.conversationService.createConversation([participantId], 'bot', {
277
- title,
278
- ...(avatar ? { avatar } : {}),
279
- icon: 'fa-solid fa-robot',
280
- metadata: axmBuildAiChatConversationMetadata(row),
281
- });
282
- }
283
- #resolveMl(value) {
284
- return this.translationService.resolve(value);
285
- }
286
- #applicationRouteSegment() {
287
- return this.sessionService.application?.name ?? 'platform';
288
- }
289
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMChatAssistLauncherService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
290
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMChatAssistLauncherService, providedIn: 'root' }); }
104
+ class AXMConversationTabService extends AXMEntityCrudServiceImpl {
291
105
  }
292
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMChatAssistLauncherService, decorators: [{
293
- type: Injectable,
294
- args: [{ providedIn: 'root' }]
295
- }] });
296
-
297
- /** Search group key — AI chat targets (assists), not conversation history. */
298
- const AXM_CONVERSATION_ASSIST_SEARCH_GROUP = 'conversation-assist';
299
- //#endregion
300
- //#region ---- Provider ----
301
- /**
302
- * Global search entries to start a new AI chat — same catalog as
303
- * {@link AXMChatWithAssistDialogComponent} / {@link AXMChatSidebarNewActionsComponent}.
304
- *
305
- * Note: the shared global search popup only queries when the text length is > 2.
306
- */
307
- class AXMConversationAssistSearchProvider {
106
+ class AXMConversationTabServiceImpl extends AXMConversationTabService {
308
107
  constructor() {
309
- this.launcher = inject(AXMChatAssistLauncherService);
310
- }
311
- async search(text) {
312
- let rows;
313
- try {
314
- rows = await this.launcher.loadTargets();
315
- }
316
- catch (error) {
317
- console.error('Failed to load AI chat targets for shortcut search:', error);
318
- return [];
319
- }
320
- const filtered = this.launcher.filterTargets(rows, text);
321
- const sorted = sortBy(filtered, (row) => this.launcher.displayName(row).toLowerCase());
322
- return sorted.map((row) => ({
323
- id: row.id,
324
- group: AXM_CONVERSATION_ASSIST_SEARCH_GROUP,
325
- title: row.title,
326
- description: row.description ?? axmChatAiTargetShortcutDescriptionKey(),
327
- icon: 'fa-solid fa-robot',
328
- data: { id: row.id, name: row.name },
329
- command: {
330
- name: CONVERSATION_START_ASSIST_CHAT_COMMAND,
331
- options: {
332
- targetId: row.id,
333
- },
334
- },
335
- }));
108
+ super(`${RootConfig.module.name}.${RootConfig.entities.tab.name}`);
336
109
  }
337
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMConversationAssistSearchProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
338
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMConversationAssistSearchProvider }); }
110
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMConversationTabServiceImpl, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
111
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMConversationTabServiceImpl }); }
339
112
  }
340
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMConversationAssistSearchProvider, decorators: [{
113
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMConversationTabServiceImpl, decorators: [{
341
114
  type: Injectable
342
- }] });
343
-
344
- //#endregion
345
- //#region ---- Provider ----
346
- /** Search group for AI assist shortcut picker (not chat/conversation history). */
347
- class AXMConversationAssistSearchDefinitionProvider {
348
- async provide(context) {
349
- context.addDefinition(AXM_CONVERSATION_ASSIST_SEARCH_GROUP, '@conversation:search.assist.group-title', AXM_CONVERSATION_ASSIST_SEARCH_GROUP, 'fa-solid fa-robot', 4, {
350
- format: {
351
- id: '{{id}}',
352
- },
353
- actions: [
354
- {
355
- name: 'start-assist-chat',
356
- type: AXPSystemActionType.View,
357
- priority: 'primary',
358
- },
359
- ],
360
- });
361
- }
362
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMConversationAssistSearchDefinitionProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
363
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMConversationAssistSearchDefinitionProvider }); }
364
- }
365
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMConversationAssistSearchDefinitionProvider, decorators: [{
366
- type: Injectable
367
- }] });
368
-
369
- class AXMConversationTabService extends AXMEntityCrudServiceImpl {
370
- }
371
- class AXMConversationTabServiceImpl extends AXMConversationTabService {
372
- constructor() {
373
- super(`${RootConfig.module.name}.${RootConfig.entities.tab.name}`);
374
- }
375
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMConversationTabServiceImpl, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
376
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMConversationTabServiceImpl }); }
377
- }
378
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMConversationTabServiceImpl, decorators: [{
379
- type: Injectable
380
- }], ctorParameters: () => [] });
115
+ }], ctorParameters: () => [] });
381
116
 
382
117
  async function tabFactory(injector) {
383
118
  const dataService = injector.get(AXMConversationTabService);
@@ -1168,708 +903,368 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
1168
903
  type: Injectable
1169
904
  }], ctorParameters: () => [{ type: i0.Injector }] });
1170
905
 
1171
- //#region ---- Imports ----
1172
- //#endregion
1173
- //#region ---- Manifest Definition ----
1174
- /**
1175
- * Conversation Module Manifest.
1176
- * Defines module metadata, features, and provider references.
1177
- */
1178
- const ConversationManifest = {
1179
- name: RootConfig.module.name,
1180
- version: '1.0.0',
1181
- title: RootConfig.module.title,
1182
- icon: RootConfig.module.icon,
1183
- i18n: RootConfig.config.i18n,
1184
- // Module dependencies
1185
- dependencies: ['NotificationManagement'],
1186
- };
1187
- //#endregion
1188
-
1189
- const AXPConversationMenuKeys = {
1190
- Conversations: 'Conversation:Menu:Conversations',
1191
- };
1192
-
1193
- const AXMPermissionsKeys = {
1194
- Conversation: {
1195
- Management: 'Conversation:Permission:Management',
1196
- },
1197
- };
1198
-
1199
- class AXMMenuProvider {
1200
- constructor() {
1201
- this.sessionService = inject(AXPSessionService);
1202
- }
1203
- async provide(context) {
1204
- const module = RootConfig;
1205
- const scope = RootConfig.config.i18n;
1206
- context.addItems([
1207
- {
1208
- name: AXPConversationMenuKeys.Conversations,
1209
- text: `@conversation:module.menus.conversations.title`,
1210
- path: `${this.sessionService.application?.name}/${module.config.route}`,
1211
- priority: 30,
1212
- icon: RootConfig.entities.room.icon,
1213
- badgeKey: 'badge-chat',
1214
- policy: {
1215
- permissions: [AXMPermissionsKeys.Conversation.Management],
1216
- },
1217
- },
1218
- ]);
1219
- }
1220
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMMenuProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1221
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMMenuProvider }); }
1222
- }
1223
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMMenuProvider, decorators: [{
1224
- type: Injectable
1225
- }] });
906
+ /** Starts a new bot conversation with the given AI assist model. */
907
+ const CONVERSATION_START_ASSIST_CHAT_COMMAND = 'Conversation:StartAssistChat';
908
+ /** Sends a user text message in the active assist chat, or starts a chat when {@code assistId} is provided. */
909
+ const CONVERSATION_SEND_ASSIST_CHAT_MESSAGE_COMMAND = 'Conversation:SendAssistChatMessage';
1226
910
 
911
+ //#region ---- Imports ----
1227
912
  //#endregion
1228
- //#region ---- Permission Definition Provider ----
1229
- class AXMPermissionDefinitionProvider {
1230
- async define(context) {
1231
- const keys = AXMPermissionsKeys.Conversation;
1232
- const modulePermissions = '@conversation:module.permissions';
1233
- context
1234
- .addGroup(RootConfig.module.name, `${modulePermissions}.title`, `${modulePermissions}.description`)
1235
- .addPermission(keys.Management, `${modulePermissions}.manage.title`, `${modulePermissions}.manage.description`)
1236
- .endPermission()
1237
- .endGroup();
1238
- }
1239
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMPermissionDefinitionProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1240
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMPermissionDefinitionProvider }); }
913
+ //#region ---- Participant & metadata ----
914
+ /** Synthetic bot participant id for assist chats. */
915
+ function axmChatAiPeerParticipantId(catalogId) {
916
+ return `assist-${catalogId.trim()}`;
1241
917
  }
1242
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMPermissionDefinitionProvider, decorators: [{
1243
- type: Injectable
1244
- }] });
1245
-
1246
- function convertChatMessageToNotification(room, message, currentUser) {
1247
- return {
1248
- channel: 'InApp',
1249
- template: {
1250
- category: 'Inbox',
1251
- prority: 'Notice',
1252
- icon: 'fa-light fa-comment',
1253
- isPinned: false,
1254
- },
1255
- title: room.title || '@conversation:chat.notification.new-message-title',
1256
- body: message.message.content,
1257
- sender: message.author,
1258
- receiver: currentUser,
1259
- content: message.message,
1260
- readAt: null,
1261
- type: 'Chat',
1262
- data: {
1263
- roomId: room.id,
1264
- },
1265
- };
918
+ /** Conversation metadata for starting an AI chat from a picker row. */
919
+ function axmBuildAiChatConversationMetadata(row) {
920
+ return { assistId: row.id };
1266
921
  }
1267
-
1268
- class AXMChatRealtimeService {
922
+ /** True when conversation metadata targets an assist row. */
923
+ function axmConversationHasAiChat(conversation) {
924
+ const assistId = conversation?.metadata?.['assistId'];
925
+ return typeof assistId === 'string' && assistId.trim().length > 0;
1269
926
  }
1270
- class AXMChatRealtimeServiceImpl extends AXMChatRealtimeService {
1271
- constructor() {
1272
- super(...arguments);
1273
- this._room$ = new Subject();
1274
- this.room$ = this._room$.asObservable();
1275
- this._message$ = new Subject();
1276
- this.message$ = this._message$.asObservable();
1277
- this._tab$ = new Subject();
1278
- this.tab$ = this._tab$.asObservable();
1279
- this._typingStatus$ = new Subject();
1280
- this.typingStatus$ = this._typingStatus$.asObservable();
1281
- }
1282
- notifyRoom(event) {
1283
- this._room$.next(event);
1284
- }
1285
- notifyMessage(event) {
1286
- this._message$.next(event);
1287
- }
1288
- notifyTab(event) {
1289
- this._tab$.next(event);
1290
- }
1291
- startTyping(user, roomId) {
1292
- this._typingStatus$.next({ roomId, user, isTyping: true });
927
+ /** Loads assist rows for Conversation AI chat pickers. */
928
+ async function axmLoadChatAiTargets(entityRegistry) {
929
+ const assists = await axmQueryEntityList(entityRegistry, RootConfig$1.entities.assist.name);
930
+ return assists
931
+ .map((raw) => ({
932
+ id: String(raw['id'] ?? ''),
933
+ name: String(raw['name'] ?? ''),
934
+ title: raw['title'],
935
+ description: raw['description'],
936
+ professionImageUrl: typeof raw['professionImageUrl'] === 'string' ? raw['professionImageUrl'] : undefined,
937
+ }))
938
+ .filter((row) => row.id.trim().length > 0)
939
+ .sort((a, b) => a.name.localeCompare(b.name, undefined, { sensitivity: 'base' }));
940
+ }
941
+ //#endregion
942
+ //#region ---- Display & filter (dialog + global search) ----
943
+ /** Resolves ML or plain string for search/display. */
944
+ function axmResolveChatAiTargetText(resolveMl, value) {
945
+ if (!value) {
946
+ return '';
1293
947
  }
1294
- stopTyping(user, roomId) {
1295
- this._typingStatus$.next({ roomId, user, isTyping: false });
948
+ if (typeof value === 'string') {
949
+ return value;
1296
950
  }
1297
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMChatRealtimeServiceImpl, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
1298
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMChatRealtimeServiceImpl, providedIn: 'root' }); }
951
+ return resolveMl(value) ?? '';
1299
952
  }
1300
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMChatRealtimeServiceImpl, decorators: [{
1301
- type: Injectable,
1302
- args: [{
1303
- providedIn: 'root',
1304
- }]
1305
- }] });
1306
-
1307
- class AXMChatService {
953
+ function axmChatAiTargetDisplayName(resolveMl, row) {
954
+ return axmResolveChatAiTargetText(resolveMl, row.title).trim() || row.name.trim() || row.id;
1308
955
  }
1309
- class AXMChatServiceImpl extends AXMChatService {
1310
- constructor() {
1311
- super(...arguments);
1312
- this.roomService = inject(AXMRoomService);
1313
- this.messageService = inject(AXMMessageService);
1314
- this.tabService = inject(AXMConversationTabService);
1315
- }
1316
- createRoom(members, title, currentUser, avatar) {
1317
- const resolvedTitle = title?.trim() || 'Chat';
1318
- const room = {
1319
- members,
1320
- /** Required by `Conversation.Room` entity validation; stable programmatic key (UI uses {@link title}). */
1321
- name: `room-${AXPDataGenerator.uuid()}`,
1322
- title: resolvedTitle,
1323
- topic: members.length > 2 ? 'group' : 'personal',
1324
- auditInfo: {
1325
- created: { at: new Date(), by: currentUser },
1326
- updated: { at: new Date(), by: currentUser },
1327
- },
1328
- type: 'chat',
1329
- avatar: avatar ?? null,
1330
- };
1331
- return this.roomService.insertOne(room).then((id) => this.roomService.getOne(id));
1332
- }
1333
- getRoom(roomId) {
1334
- return this.roomService.getOne(roomId);
1335
- }
1336
- async listRooms(skip = 0, take = 100) {
1337
- return this.roomService.query({
1338
- skip,
1339
- take,
1340
- filter: { field: 'type', value: 'chat', operator: { type: 'equal' } },
1341
- });
1342
- }
1343
- updateRoom(roomId, data, currentUser) {
1344
- const update = { ...data, auditInfo: { updated: { at: new Date(), by: currentUser } } };
1345
- return this.roomService.updateOne(roomId, update);
1346
- }
1347
- async deleteRoom(roomId) {
1348
- await this.roomService.deleteOne(roomId);
1349
- return true;
1350
- }
1351
- createTab(data) {
1352
- return this.tabService.insertOne(data).then((id) => this.tabService.getOne(id));
1353
- }
1354
- getTab(tabId) {
1355
- return this.tabService.getOne(tabId);
1356
- }
1357
- listTabs(skip = 0, take = 100) {
1358
- return this.tabService.query({ skip, take });
1359
- }
1360
- updateTab(tabId, data) {
1361
- return this.tabService.updateOne(tabId, data);
1362
- }
1363
- async deleteTab(tabId) {
1364
- await this.tabService.deleteOne(tabId);
1365
- return true;
1366
- }
1367
- sendMessage(roomId, content, author, contentType = 'text', replyId) {
1368
- const messageContent = { content, contentType };
1369
- const message = {
1370
- roomId,
1371
- message: messageContent,
1372
- author,
1373
- replyId,
1374
- auditInfo: {
1375
- created: { at: new Date(), by: author },
1376
- updated: { at: new Date(), by: author },
1377
- },
1378
- reactions: [],
1379
- seen: [],
1380
- };
1381
- return this.messageService.insertOne({ ...message }).then((id) => this.messageService.getOne(id));
1382
- }
1383
- async getMessages(roomId, skip = 0, take = 99) {
1384
- return this.messageService.query({
1385
- skip,
1386
- take,
1387
- filter: { field: 'roomId', value: roomId, operator: { type: 'equal' } },
1388
- sort: [{ field: 'created.at', dir: 'desc' }],
1389
- });
1390
- }
1391
- getMessage(messageId) {
1392
- return this.messageService.getOne(messageId);
1393
- }
1394
- editMessage(messageId, content, currentUser, contentType = 'text') {
1395
- const messageContent = { content, contentType };
1396
- return this.messageService.updateOne(messageId, {
1397
- message: messageContent,
1398
- auditInfo: {
1399
- updated: { at: new Date(), by: currentUser },
1400
- },
1401
- });
1402
- }
1403
- async deleteMessage(messageId) {
1404
- await this.messageService.deleteOne(messageId);
1405
- return true;
1406
- }
1407
- pinMessage(messageId, isPinned, currentUser) {
1408
- return this.messageService.updateOne(messageId, {
1409
- isPinned,
1410
- auditInfo: {
1411
- updated: { at: new Date(), by: currentUser },
1412
- },
1413
- });
1414
- }
1415
- updateReactions(messageId, reactions, currentUser) {
1416
- return this.messageService.updateOne(messageId, {
1417
- reactions,
1418
- auditInfo: {
1419
- updated: { at: new Date(), by: currentUser },
1420
- },
1421
- });
1422
- }
1423
- getReactions(messageId) {
1424
- return this.messageService.getOne(messageId).then((m) => m.reactions || []);
956
+ function axmChatAiTargetDisplayDescription(resolveMl, row) {
957
+ if (!row.description) {
958
+ return undefined;
1425
959
  }
1426
- updateSeen(messageId, seen, currentUser) {
1427
- return this.messageService.updateOne(messageId, {
1428
- seen,
1429
- auditInfo: {
1430
- updated: { at: new Date(), by: currentUser },
1431
- },
1432
- });
960
+ const text = axmResolveChatAiTargetText(resolveMl, row.description).trim();
961
+ return text || undefined;
962
+ }
963
+ function axmChatAiTargetAvatarUrl(row) {
964
+ const url = row.professionImageUrl?.trim();
965
+ return url ? url : null;
966
+ }
967
+ /** Fallback i18n key for rows with no catalog description. */
968
+ function axmChatAiTargetShortcutDescriptionKey() {
969
+ return '@conversation:search.assist.shortcut-description';
970
+ }
971
+ /** Same filter as {@link AXMChatWithAssistDialogComponent} target list search. */
972
+ function axmFilterChatAiTargets(resolveMl, rows, query) {
973
+ const q = query.trim().toLowerCase();
974
+ if (!q) {
975
+ return rows;
1433
976
  }
1434
- getSeenBy(messageId) {
1435
- return this.messageService.getOne(messageId).then((m) => m.seen || []);
977
+ return rows.filter((r) => {
978
+ const titleText = axmResolveChatAiTargetText(resolveMl, r.title).toLowerCase();
979
+ return (r.name.toLowerCase().includes(q) ||
980
+ titleText.includes(q) ||
981
+ axmResolveChatAiTargetText(resolveMl, r.description).toLowerCase().includes(q));
982
+ });
983
+ }
984
+ //#endregion
985
+ //#region ---- Entity list query ----
986
+ async function axmQueryEntityList(entityRegistry, entityName) {
987
+ const entity = await entityRegistry.resolve(RootConfig$1.module.name, entityName);
988
+ const execute = entity.queries?.list?.execute;
989
+ if (!execute) {
990
+ throw new Error(`${entityName} entity has no list query.`);
1436
991
  }
1437
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMChatServiceImpl, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
1438
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMChatServiceImpl, providedIn: 'root' }); }
992
+ const res = await execute({
993
+ skip: 0,
994
+ take: 500,
995
+ sort: [{ name: 'name', dir: 'asc' }],
996
+ });
997
+ return res.items ?? [];
1439
998
  }
1440
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMChatServiceImpl, decorators: [{
1441
- type: Injectable,
1442
- args: [{
1443
- providedIn: 'root',
1444
- }]
1445
- }] });
999
+ //#endregion
1446
1000
 
1447
- class AXMChatManagementService {
1001
+ //#region ---- Imports ----
1002
+ //#endregion
1003
+ //#region ---- Service ----
1004
+ /**
1005
+ * Starts bot conversations from catalog assist rows,
1006
+ * shared by global search shortcuts and {@link AXMConversationStartAssistChatCommand}.
1007
+ */
1008
+ class AXMChatAssistLauncherService {
1448
1009
  constructor() {
1449
- this.chatService = inject(AXMChatService);
1010
+ this.conversationService = inject(AXConversationService);
1011
+ this.entityRegistry = inject(AXPEntityDefinitionRegistryService);
1012
+ this.translationService = inject(AXTranslationService);
1450
1013
  this.sessionService = inject(AXPSessionService);
1451
- this.usersService = inject(AXMUsersEntityService);
1452
- this.realtimeService = inject(AXMChatRealtimeService);
1453
- this.notificationConnectorService = inject(AXMNotificationConnectorService);
1454
- this.userCache = new Map();
1455
- this.messagePageSize = 99;
1456
- }
1457
- getCurrentUser() {
1458
- const user = this.sessionService.user;
1459
- if (!user) {
1460
- throw new Error('No authenticated user found.');
1461
- }
1462
- return {
1463
- id: user.id,
1464
- type: 'user',
1465
- fullName: user.title?.trim(),
1466
- username: user.name?.trim(),
1467
- };
1468
- }
1469
- async getUserInfo(userId) {
1470
- const cached = this.userCache.get(userId);
1471
- if (cached) {
1472
- return cached;
1473
- }
1474
- try {
1475
- const user = await this.usersService.getOne(userId);
1476
- const ref = {
1477
- id: user.id,
1478
- type: 'user',
1479
- fullName: `${user.displayName}`.trim(),
1480
- username: user.username?.trim(),
1481
- };
1482
- this.userCache.set(userId, ref);
1483
- return ref;
1484
- }
1485
- catch (error) {
1486
- console.error(`Failed to get user info for ID: ${userId}`, error);
1487
- const fallback = {
1488
- id: userId,
1489
- type: 'user',
1490
- fullName: 'Unknown User',
1491
- username: 'Unknown User',
1492
- };
1493
- this.userCache.set(userId, fallback);
1494
- return fallback;
1495
- }
1496
- }
1497
- async formatMessage(message) {
1498
- if (message.author && !message.author.fullName) {
1499
- const authorInfo = await this.getUserInfo(message.author.id);
1500
- return {
1501
- ...message,
1502
- author: authorInfo,
1503
- };
1504
- }
1505
- return message;
1506
- }
1507
- async formatRoom(room) {
1508
- const { items } = await this.getMessages(room.id, 0, this.messagePageSize);
1509
- const lastMessage = items.length > 0 ? items[0] : undefined;
1510
- const currentUserId = this.getCurrentUser().id;
1511
- const unreadCount = items.filter((message) => {
1512
- const isFromCurrentUser = message.author.id === currentUserId;
1513
- const isReadByCurrentUser = (message.seen || []).some((seen) => seen.author.id === currentUserId);
1514
- return !isFromCurrentUser && !isReadByCurrentUser;
1515
- }).length;
1516
- const members = await Promise.all(room.members.map(async (member) => {
1517
- if (member.fullName) {
1518
- return member;
1519
- }
1520
- return this.getUserInfo(member.id);
1521
- }));
1522
- return {
1523
- ...room,
1524
- lastMessage,
1525
- unreadCount,
1526
- members: members.filter((m) => m.id !== currentUserId),
1527
- };
1528
- }
1529
- async mapWithConcurrency(items, limit, fn) {
1530
- const results = new Array(items.length);
1531
- let i = 0;
1532
- const worker = async () => {
1533
- while (true) {
1534
- const idx = i++;
1535
- if (idx >= items.length)
1536
- break;
1537
- try {
1538
- results[idx] = await fn(items[idx]);
1539
- }
1540
- catch (err) {
1541
- console.error('AXMChatManagementService: item processing failed', err);
1542
- results[idx] = undefined;
1543
- }
1544
- }
1545
- };
1546
- const workers = Array(Math.min(limit, items.length))
1547
- .fill(0)
1548
- .map(() => worker());
1549
- await Promise.all(workers);
1550
- return results.filter((r) => r !== undefined);
1551
- }
1552
- async createRoom(memberIds, title, avatar) {
1553
- if (memberIds.length === 0) {
1554
- throw new Error('At least one member is required to create a room');
1555
- }
1556
- const currentUser = this.getCurrentUser();
1557
- const allMemberIds = [...new Set([...memberIds, currentUser.id])];
1558
- const memberReferences = await Promise.all(allMemberIds.map((id) => (id === currentUser.id ? Promise.resolve(currentUser) : this.getUserInfo(id))));
1559
- const newRoom = await this.chatService.createRoom(memberReferences, title, currentUser, avatar || undefined);
1560
- const newChatRoom = await this.formatRoom(newRoom);
1561
- this.realtimeService.notifyRoom({ type: 'add', payload: newChatRoom });
1562
- return newChatRoom;
1563
- }
1564
- async getRoom(roomId) {
1565
- const room = await this.chatService.getRoom(roomId);
1566
- if (!room) {
1567
- throw new Error(`Chat room with ID ${roomId} not found.`);
1568
- }
1569
- return this.formatRoom(room);
1570
- }
1571
- async listRooms(skip = 0, take = 100) {
1572
- const { items, total } = await this.chatService.listRooms(skip, take);
1573
- const chatRooms = await this.mapWithConcurrency(items, 6, (room) => this.formatRoom(room));
1574
- const sorted = [...chatRooms].sort((a, b) => {
1575
- const ad = a.lastMessage?.auditInfo?.created?.at ? new Date(a.lastMessage.auditInfo.created.at).getTime() : 0;
1576
- const bd = b.lastMessage?.auditInfo?.created?.at ? new Date(b.lastMessage.auditInfo.created.at).getTime() : 0;
1577
- return bd - ad;
1578
- });
1579
- return { items: sorted, total };
1580
- }
1581
- async updateRoom(roomId, data) {
1582
- const currentUser = this.getCurrentUser();
1583
- const updated = await this.chatService.updateRoom(roomId, data, currentUser);
1584
- try {
1585
- const formatted = await this.formatRoom(updated);
1586
- this.realtimeService.notifyRoom({ type: 'update', payload: formatted });
1587
- }
1588
- catch (err) {
1589
- console.error('Failed to notify room update', err);
1590
- }
1591
- return updated;
1592
- }
1593
- async deleteRoom(roomId) {
1594
- const result = await this.chatService.deleteRoom(roomId);
1595
- if (result) {
1596
- this.realtimeService.notifyRoom({ type: 'remove', payload: roomId });
1597
- }
1598
- return result;
1599
- }
1600
- async addParticipant(roomId, userId) {
1601
- const room = await this.chatService.getRoom(roomId);
1602
- if (room.members.some((m) => m.id === userId))
1603
- return room;
1604
- const userRef = await this.getUserInfo(userId);
1605
- const updatedMembers = [...room.members, userRef];
1606
- const currentUser = this.getCurrentUser();
1607
- const updated = await this.chatService.updateRoom(roomId, { members: updatedMembers }, currentUser);
1608
- try {
1609
- const formatted = await this.formatRoom(updated);
1610
- this.realtimeService.notifyRoom({ type: 'update', payload: formatted });
1611
- }
1612
- catch (err) {
1613
- console.error('Failed to notify add participant', err);
1614
- }
1615
- return updated;
1014
+ this.router = inject(Router);
1015
+ this.toastService = inject(AXToastService);
1016
+ this.targetsCache = null;
1017
+ this.loadPromise = null;
1616
1018
  }
1617
- async removeParticipant(roomId, userId) {
1618
- const room = await this.chatService.getRoom(roomId);
1619
- const updatedMembers = room.members.filter((member) => member.id !== userId);
1620
- const currentUser = this.getCurrentUser();
1621
- const updated = await this.chatService.updateRoom(roomId, { members: updatedMembers }, currentUser);
1622
- try {
1623
- const formatted = await this.formatRoom(updated);
1624
- this.realtimeService.notifyRoom({ type: 'update', payload: formatted });
1019
+ async loadTargets(force = false) {
1020
+ if (!force && this.targetsCache) {
1021
+ return this.targetsCache;
1625
1022
  }
1626
- catch (err) {
1627
- console.error('Failed to notify remove participant', err);
1023
+ if (!force && this.loadPromise) {
1024
+ return this.loadPromise;
1628
1025
  }
1629
- return updated;
1630
- }
1631
- async createTab(data) {
1632
- const newTab = await this.chatService.createTab(data);
1633
- this.realtimeService.notifyTab({ type: 'add', payload: newTab });
1634
- return newTab;
1635
- }
1636
- getTab(tabId) {
1637
- return this.chatService.getTab(tabId);
1638
- }
1639
- listTabs(skip, take) {
1640
- return this.chatService.listTabs(skip, take);
1641
- }
1642
- async updateTab(tabId, data) {
1643
- const updated = await this.chatService.updateTab(tabId, data);
1026
+ this.loadPromise = axmLoadChatAiTargets(this.entityRegistry);
1644
1027
  try {
1645
- this.realtimeService.notifyTab({ type: 'update', payload: updated });
1028
+ this.targetsCache = await this.loadPromise;
1029
+ return this.targetsCache;
1646
1030
  }
1647
- catch (err) {
1648
- console.error('Failed to notify tab update', err);
1031
+ finally {
1032
+ this.loadPromise = null;
1649
1033
  }
1650
- return updated;
1651
1034
  }
1652
- async deleteTab(tabId) {
1653
- const result = await this.chatService.deleteTab(tabId);
1654
- if (result) {
1655
- this.realtimeService.notifyTab({ type: 'remove', payload: tabId });
1656
- }
1657
- return result;
1035
+ displayName(row) {
1036
+ return axmChatAiTargetDisplayName(this.#resolveMl.bind(this), row);
1658
1037
  }
1659
- async addIncludeRoomToTab(tabId, roomId) {
1660
- const tab = await this.getTab(tabId);
1661
- const room = await this.chatService.getRoom(roomId);
1662
- if (tab && room) {
1663
- if (tab.includeRooms.some((r) => r.id === roomId)) {
1664
- return tab;
1665
- }
1666
- const includeRooms = [...tab.includeRooms, room];
1667
- const excludeRooms = tab.excludeRooms.filter((r) => r.id !== roomId);
1668
- return this.updateTab(tabId, { includeRooms, excludeRooms });
1669
- }
1670
- else {
1671
- throw new Error(`Tab with ID ${tabId} or room with ID ${roomId} not found.`);
1672
- }
1038
+ displayDescription(row) {
1039
+ return axmChatAiTargetDisplayDescription(this.#resolveMl.bind(this), row);
1673
1040
  }
1674
- async removeIncludeRoomFromTab(tabId, roomId) {
1675
- const tab = await this.getTab(tabId);
1676
- if (tab) {
1677
- if (tab.includeRooms.some((r) => r.id === roomId)) {
1678
- const updatedRooms = tab.includeRooms.filter((r) => r.id !== roomId);
1679
- return this.updateTab(tabId, { includeRooms: updatedRooms });
1680
- }
1681
- else {
1682
- throw new Error(`${tabId} tab does not include room with ID ${roomId}.`);
1683
- }
1684
- }
1685
- else {
1686
- throw new Error(`Tab with ID ${tabId} not found.`);
1687
- }
1041
+ targetAvatarUrl(row) {
1042
+ return axmChatAiTargetAvatarUrl(row);
1688
1043
  }
1689
- async addExcludeRoomToTab(tabId, roomId) {
1690
- const tab = await this.getTab(tabId);
1691
- const room = await this.chatService.getRoom(roomId);
1692
- if (tab && room) {
1693
- if (tab.excludeRooms.some((r) => r.id === roomId)) {
1694
- return tab;
1695
- }
1696
- const excludeRooms = [...tab.excludeRooms, room];
1697
- const includeRooms = tab.includeRooms.filter((r) => r.id !== roomId);
1698
- return this.updateTab(tabId, { excludeRooms, includeRooms });
1699
- }
1700
- else {
1701
- throw new Error(`Tab with ID ${tabId} or room with ID ${roomId} not found.`);
1702
- }
1044
+ filterTargets(rows, query) {
1045
+ return axmFilterChatAiTargets(this.#resolveMl.bind(this), rows, query);
1703
1046
  }
1704
- async removeExcludeRoomFromTab(tabId, roomId) {
1705
- const tab = await this.getTab(tabId);
1706
- if (tab) {
1707
- if (tab.excludeRooms.some((r) => r.id === roomId)) {
1708
- const updatedRooms = tab.excludeRooms.filter((r) => r.id !== roomId);
1709
- return this.updateTab(tabId, { excludeRooms: updatedRooms });
1710
- }
1711
- else {
1712
- throw new Error(`${tabId} tab does not exclude room with ID ${roomId}.`);
1713
- }
1047
+ async startAssistChat(options) {
1048
+ const targetId = (options.targetId ?? options.assistId)?.trim();
1049
+ if (!targetId) {
1050
+ return null;
1714
1051
  }
1715
- else {
1716
- throw new Error(`Tab with ID ${tabId} not found.`);
1052
+ const rows = await this.loadTargets();
1053
+ const row = rows.find((r) => r.id === targetId);
1054
+ if (!row) {
1055
+ const message = await this.translationService.translateAsync('@conversation:chat.assist-dialog.errors.start-chat');
1056
+ this.toastService.danger(message);
1057
+ return null;
1717
1058
  }
1718
- }
1719
- async sendMessage(roomId, content, contentType = 'text', replyId, userId) {
1720
- const author = userId ? await this.getUserInfo(userId) : this.getCurrentUser();
1721
- const newMessage = await this.chatService.sendMessage(roomId, content, author, contentType, replyId);
1722
- const formattedMessage = await this.formatMessage(newMessage);
1723
- this.realtimeService.notifyMessage({ type: 'add', payload: formattedMessage });
1724
- // Create a notification when a new message is sent by someone else
1725
1059
  try {
1726
- const currentUser = this.getCurrentUser();
1727
- if (formattedMessage.author.id !== currentUser.id) {
1728
- const baseRoom = await this.chatService.getRoom(formattedMessage.roomId);
1729
- const notification = convertChatMessageToNotification({ id: baseRoom.id, title: baseRoom.title }, formattedMessage, currentUser);
1730
- await this.notificationConnectorService.create({
1731
- ...notification,
1732
- id: formattedMessage.id,
1733
- entityName: 'notifications',
1734
- createAt: new Date(),
1735
- });
1060
+ const conversation = await this.#createTargetConversation(row);
1061
+ await this.conversationService.selectConversation(conversation.id);
1062
+ if (options.navigate !== false) {
1063
+ await this.router.navigate([this.#applicationRouteSegment(), 'chat', conversation.id]);
1736
1064
  }
1065
+ return { conversation };
1737
1066
  }
1738
1067
  catch (error) {
1739
- // Non-blocking: log and continue
1740
- console.error('Failed to create notification for new message', error);
1741
- }
1742
- return formattedMessage;
1743
- }
1744
- async getMessages(roomId, skip, take) {
1745
- const result = await this.chatService.getMessages(roomId, skip, take);
1746
- const formattedMessages = await Promise.all(result.items.map((m) => this.formatMessage(m)));
1747
- return { items: formattedMessages, total: result.total };
1748
- }
1749
- async getMessage(messageId) {
1750
- const message = await this.chatService.getMessage(messageId);
1751
- return this.formatMessage(message);
1752
- }
1753
- async editMessage(messageId, content, contentType = 'text') {
1754
- const currentUser = this.getCurrentUser();
1755
- const updatedMessage = await this.chatService.editMessage(messageId, content, currentUser, contentType);
1756
- this.realtimeService.notifyMessage({ type: 'update', payload: await this.formatMessage(updatedMessage) });
1757
- return updatedMessage;
1758
- }
1759
- async deleteMessage(messageId) {
1760
- const result = await this.chatService.deleteMessage(messageId);
1761
- if (result) {
1762
- this.realtimeService.notifyMessage({ type: 'remove', payload: messageId });
1763
- }
1764
- return result;
1765
- }
1766
- async replyMessage(replyToMessageId, content, contentType = 'text') {
1767
- const originalMessage = await this.chatService.getMessage(replyToMessageId);
1768
- return this.sendMessage(originalMessage.roomId, content, contentType, replyToMessageId);
1769
- }
1770
- async pinMessage(messageId) {
1771
- const currentUser = this.getCurrentUser();
1772
- return this.chatService.pinMessage(messageId, true, currentUser);
1773
- }
1774
- async unpinMessage(messageId) {
1775
- const currentUser = this.getCurrentUser();
1776
- return this.chatService.pinMessage(messageId, false, currentUser);
1777
- }
1778
- async addReaction(messageId, type) {
1779
- const author = this.getCurrentUser();
1780
- const message = await this.chatService.getMessage(messageId);
1781
- const reactions = message.reactions || [];
1782
- if (reactions.some((r) => r.author.id === author.id && r.type === type)) {
1783
- return message;
1068
+ console.error('Failed to start AI chat:', error);
1069
+ const message = await this.translationService.translateAsync('@conversation:chat.assist-dialog.errors.start-chat');
1070
+ this.toastService.danger(message);
1071
+ return null;
1784
1072
  }
1785
- const updatedReactions = [...reactions, { author, type }];
1786
- const res = await this.chatService.updateReactions(messageId, updatedReactions, author);
1787
- this.realtimeService.notifyMessage({ type: 'update', payload: await this.formatMessage(res) });
1788
- return res;
1789
1073
  }
1790
- async removeReaction(messageId, type) {
1791
- const author = this.getCurrentUser();
1792
- const message = await this.chatService.getMessage(messageId);
1793
- const updatedReactions = (message.reactions || []).filter((r) => !(r.author.id === author.id && r.type === type));
1794
- const res = await this.chatService.updateReactions(messageId, updatedReactions, author);
1795
- this.realtimeService.notifyMessage({ type: 'update', payload: await this.formatMessage(res) });
1796
- return res;
1074
+ async #createTargetConversation(row) {
1075
+ const participantId = axmChatAiPeerParticipantId(row.id);
1076
+ const title = this.displayName(row);
1077
+ const avatar = this.targetAvatarUrl(row);
1078
+ return this.conversationService.createConversation([participantId], 'bot', {
1079
+ title,
1080
+ ...(avatar ? { avatar } : {}),
1081
+ icon: 'fa-solid fa-robot',
1082
+ metadata: axmBuildAiChatConversationMetadata(row),
1083
+ });
1797
1084
  }
1798
- async getReactions(messageId) {
1799
- return this.chatService.getReactions(messageId);
1085
+ #resolveMl(value) {
1086
+ return this.translationService.resolve(value);
1800
1087
  }
1801
- async markSeen(messageId, notify = true) {
1802
- const author = this.getCurrentUser();
1803
- const message = await this.chatService.getMessage(messageId);
1804
- const seen = message.seen || [];
1805
- if (seen.some((s) => s.author.id === author.id)) {
1806
- return message;
1807
- }
1808
- const updatedSeen = [...seen, { author, type: 'read' }];
1809
- const updatedMessage = await this.chatService.updateSeen(messageId, updatedSeen, author);
1810
- if (notify) {
1811
- this.realtimeService.notifyRoom({ type: 'seen', payload: updatedMessage.roomId });
1812
- }
1813
- return updatedMessage;
1088
+ #applicationRouteSegment() {
1089
+ return this.sessionService.application?.name ?? 'platform';
1814
1090
  }
1815
- async getSeenBy(messageId) {
1816
- return this.chatService.getSeenBy(messageId);
1091
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMChatAssistLauncherService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1092
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMChatAssistLauncherService, providedIn: 'root' }); }
1093
+ }
1094
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMChatAssistLauncherService, decorators: [{
1095
+ type: Injectable,
1096
+ args: [{ providedIn: 'root' }]
1097
+ }] });
1098
+
1099
+ /** Search group key — AI chat targets (assists), not conversation history. */
1100
+ const AXM_CONVERSATION_ASSIST_SEARCH_GROUP = 'conversation-assist';
1101
+ //#endregion
1102
+ //#region ---- Provider ----
1103
+ /**
1104
+ * Global search entries to start a new AI chat — same catalog as
1105
+ * {@link AXMChatWithAssistDialogComponent} / {@link AXMChatSidebarNewActionsComponent}.
1106
+ *
1107
+ * Note: the shared global search popup only queries when the text length is > 2.
1108
+ */
1109
+ class AXMConversationAssistSearchProvider {
1110
+ constructor() {
1111
+ this.launcher = inject(AXMChatAssistLauncherService);
1817
1112
  }
1818
- async markRoomSeen(roomId) {
1113
+ async search(text) {
1114
+ let rows;
1819
1115
  try {
1820
- if (!roomId) {
1821
- return true;
1822
- }
1823
- const currentUserId = this.getCurrentUser().id;
1824
- const take = this.messagePageSize;
1825
- let skip = 0;
1826
- let pageCount = 0;
1827
- let processedAny = false;
1828
- const maxPages = 10; // safety guard
1829
- while (pageCount < maxPages) {
1830
- const { items } = await this.getMessages(roomId, skip, take);
1831
- if (items.length === 0) {
1832
- break;
1833
- }
1834
- const unreadMessages = items.filter((message) => message.author.id !== currentUserId && !message.seen?.some((s) => s.author.id === currentUserId));
1835
- if (unreadMessages.length > 0) {
1836
- await Promise.all(unreadMessages.map((message) => this.markSeen(message.id, false)));
1837
- processedAny = true;
1838
- }
1839
- if (items.length < take) {
1840
- break;
1841
- }
1842
- skip += take;
1843
- pageCount++;
1844
- }
1845
- if (processedAny) {
1846
- this.realtimeService.notifyRoom({ type: 'seen', payload: roomId });
1847
- }
1848
- return true;
1116
+ rows = await this.launcher.loadTargets();
1849
1117
  }
1850
1118
  catch (error) {
1851
- console.error(`Error marking room ${roomId} as seen:`, error);
1852
- return false;
1119
+ console.error('Failed to load AI chat targets for shortcut search:', error);
1120
+ return [];
1853
1121
  }
1122
+ const filtered = this.launcher.filterTargets(rows, text);
1123
+ const sorted = sortBy(filtered, (row) => this.launcher.displayName(row).toLowerCase());
1124
+ return sorted.map((row) => ({
1125
+ id: row.id,
1126
+ group: AXM_CONVERSATION_ASSIST_SEARCH_GROUP,
1127
+ title: row.title,
1128
+ description: row.description ?? axmChatAiTargetShortcutDescriptionKey(),
1129
+ icon: 'fa-solid fa-robot',
1130
+ data: { id: row.id, name: row.name },
1131
+ command: {
1132
+ name: CONVERSATION_START_ASSIST_CHAT_COMMAND,
1133
+ options: {
1134
+ targetId: row.id,
1135
+ },
1136
+ },
1137
+ }));
1138
+ }
1139
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMConversationAssistSearchProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1140
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMConversationAssistSearchProvider }); }
1141
+ }
1142
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMConversationAssistSearchProvider, decorators: [{
1143
+ type: Injectable
1144
+ }] });
1145
+
1146
+ //#endregion
1147
+ //#region ---- Provider ----
1148
+ /** Search group for AI assist shortcut picker (not chat/conversation history). */
1149
+ class AXMConversationAssistSearchDefinitionProvider {
1150
+ async provide(context) {
1151
+ context.addDefinition(AXM_CONVERSATION_ASSIST_SEARCH_GROUP, '@conversation:search.assist.group-title', AXM_CONVERSATION_ASSIST_SEARCH_GROUP, 'fa-solid fa-robot', 4, {
1152
+ format: {
1153
+ id: '{{id}}',
1154
+ },
1155
+ actions: [
1156
+ {
1157
+ name: 'start-assist-chat',
1158
+ type: AXPSystemActionType.View,
1159
+ priority: 'primary',
1160
+ },
1161
+ ],
1162
+ });
1163
+ }
1164
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMConversationAssistSearchDefinitionProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1165
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMConversationAssistSearchDefinitionProvider }); }
1166
+ }
1167
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMConversationAssistSearchDefinitionProvider, decorators: [{
1168
+ type: Injectable
1169
+ }] });
1170
+
1171
+ //#region ---- Imports ----
1172
+ //#endregion
1173
+ //#region ---- Manifest Definition ----
1174
+ /**
1175
+ * Conversation Module Manifest.
1176
+ * Defines module metadata, features, and provider references.
1177
+ */
1178
+ const ConversationManifest = {
1179
+ name: RootConfig.module.name,
1180
+ version: '1.0.0',
1181
+ title: RootConfig.module.title,
1182
+ icon: RootConfig.module.icon,
1183
+ i18n: RootConfig.config.i18n,
1184
+ // Module dependencies
1185
+ dependencies: ['NotificationManagement'],
1186
+ };
1187
+ //#endregion
1188
+
1189
+ const AXPConversationMenuKeys = {
1190
+ Conversations: 'Conversation:Menu:Conversations',
1191
+ };
1192
+
1193
+ const AXMPermissionsKeys = {
1194
+ Conversation: {
1195
+ Management: 'Conversation:Permission:Management',
1196
+ },
1197
+ };
1198
+
1199
+ class AXMMenuProvider {
1200
+ constructor() {
1201
+ this.sessionService = inject(AXPSessionService);
1854
1202
  }
1855
- async startTyping(roomId, userId) {
1856
- const user = userId ? await this.getUserInfo(userId) : this.getCurrentUser();
1857
- this.realtimeService.startTyping(user, roomId);
1203
+ async provide(context) {
1204
+ const module = RootConfig;
1205
+ const scope = RootConfig.config.i18n;
1206
+ context.addItems([
1207
+ {
1208
+ name: AXPConversationMenuKeys.Conversations,
1209
+ text: `@conversation:module.menus.conversations.title`,
1210
+ path: `${this.sessionService.application?.name}/${module.config.route}`,
1211
+ priority: 30,
1212
+ icon: RootConfig.entities.room.icon,
1213
+ badgeKey: 'badge-chat',
1214
+ policy: {
1215
+ permissions: [AXMPermissionsKeys.Conversation.Management],
1216
+ },
1217
+ },
1218
+ ]);
1858
1219
  }
1859
- async stopTyping(roomId, userId) {
1860
- const user = userId ? await this.getUserInfo(userId) : this.getCurrentUser();
1861
- this.realtimeService.stopTyping(user, roomId);
1220
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMMenuProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1221
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMMenuProvider }); }
1222
+ }
1223
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMMenuProvider, decorators: [{
1224
+ type: Injectable
1225
+ }] });
1226
+
1227
+ //#endregion
1228
+ //#region ---- Permission Definition Provider ----
1229
+ class AXMPermissionDefinitionProvider {
1230
+ async define(context) {
1231
+ const keys = AXMPermissionsKeys.Conversation;
1232
+ const modulePermissions = '@conversation:module.permissions';
1233
+ context
1234
+ .addGroup(RootConfig.module.name, `${modulePermissions}.title`, `${modulePermissions}.description`)
1235
+ .addPermission(keys.Management, `${modulePermissions}.manage.title`, `${modulePermissions}.manage.description`)
1236
+ .endPermission()
1237
+ .endGroup();
1862
1238
  }
1863
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMChatManagementService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1864
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMChatManagementService, providedIn: 'root' }); }
1239
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMPermissionDefinitionProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1240
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMPermissionDefinitionProvider }); }
1865
1241
  }
1866
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMChatManagementService, decorators: [{
1867
- type: Injectable,
1868
- args: [{
1869
- providedIn: 'root',
1870
- }]
1242
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMPermissionDefinitionProvider, decorators: [{
1243
+ type: Injectable
1871
1244
  }] });
1872
1245
 
1246
+ //#region ---- Imports ----
1247
+ //#endregion
1248
+ //#region ---- Task Badge Provider ----
1249
+ /** Provides a live unread conversation count for header/task badges. */
1250
+ class AXMChatBadgeProviderSimple {
1251
+ //#endregion
1252
+ constructor() {
1253
+ //#region ---- Services & Dependencies ----
1254
+ this.conversationService = inject(AXConversationService);
1255
+ //#endregion
1256
+ //#region ---- Signals & Properties ----
1257
+ this.key = 'badge-chat';
1258
+ this.count = computed(() => this.conversationService.conversations().filter((conversation) => conversation.unreadCount > 0).length, ...(ngDevMode ? [{ debugName: "count" }] : /* istanbul ignore next */ []));
1259
+ void this.conversationService.loadConversations();
1260
+ }
1261
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMChatBadgeProviderSimple, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1262
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMChatBadgeProviderSimple }); }
1263
+ }
1264
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMChatBadgeProviderSimple, decorators: [{
1265
+ type: Injectable
1266
+ }], ctorParameters: () => [] });
1267
+
1873
1268
  //#region ---- Imports ----
1874
1269
  //#endregion
1875
1270
  //#region ---- Module cache (sync reads for action visibility) ----
@@ -3275,7 +2670,7 @@ class AXMChatComponent extends AXPPageLayoutBaseComponent {
3275
2670
  return this.activatedRoute.snapshot.parent?.paramMap.get('app') || 'platform';
3276
2671
  }
3277
2672
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMChatComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
3278
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXMChatComponent, isStandalone: true, selector: "axm-chat", host: { listeners: { "keydown.escape": "onContainerEscape()" }, properties: { "tabindex": "\"-1\"" } }, usesInheritance: true, ngImport: i0, template: "<axp-page-layout #container axConversationContainer>\n <!-- Sidebar: Always visible on desktop, visible on mobile only when no conversation is selected -->\n\n <axp-layout-start-side class=\"ax-border-e ax-lightest-surface ax-h-full\">\n <axp-layout-content class=\"ax-flex ax-flex-col ax-min-h-0 ax-max-w-80\">\n <div class=\"ax-h-full ax-flex ax-flex-col ax-shrink-0\">\n <ax-conversation-sidebar (conversationSelected)=\"onConversationSelected($event.id)\" class=\"ax-group\">\n <ax-suffix>\n <div class=\"ax-flex ax-h-14 ax-shrink-0 ax-items-center ax-justify-end ax-overflow-hidden\">\n <axm-chat-sidebar-new-actions\n class=\"group-hover:!ax-translate-y-0 !ax-translate-y-36 ax-transition-transform ax-duration-200\"\n (conversationCreated)=\"onConversationSelected($event)\" />\n </div>\n </ax-suffix>\n </ax-conversation-sidebar>\n </div>\n </axp-layout-content>\n </axp-layout-start-side>\n\n <!-- Chat content: Always visible on desktop, visible on mobile only when a conversation is selected -->\n\n <axp-page-content class=\"ax-h-full ax-overflow-hidden !ax-p-0 ax-flex ax-min-h-0 ax-flex-col\">\n @if (showChatList()) {\n <ax-conversation-sidebar (conversationSelected)=\"onConversationSelected($event.id)\" class=\"ax-group\">\n <ax-suffix>\n <div class=\"ax-flex ax-h-14 ax-shrink-0 ax-items-center ax-justify-end ax-overflow-hidden\">\n <axm-chat-sidebar-new-actions\n class=\"group-hover:!ax-translate-y-0 !ax-translate-y-36 ax-transition-transform ax-duration-200\"\n (conversationCreated)=\"onConversationSelected($event)\" />\n </div>\n </ax-suffix>\n </ax-conversation-sidebar>\n } @else {\n <div class=\"ax-flex ax-h-full ax-min-h-0 ax-flex-1 ax-flex-col\">\n <ax-conversation-info-bar class=\"ax-shadow-md\">\n <ax-prefix>\n <!-- Back button visible only on mobile -->\n @if (deviceService.isMobileDevice()) {\n <ax-button look=\"blank\" (onClick)=\"openChatList()\">\n <ax-icon icon=\"fa-light fa-bars\"></ax-icon>\n </ax-button>\n } @else {\n <ax-button class=\"ax-rounded-full\" look=\"blank\" (onClick)=\"onContainerEscape()\" aria-label=\"Close Chat\">\n <ax-icon icon=\"fa-light fa-xmark ax-text-xl\"></ax-icon>\n </ax-button>\n }\n </ax-prefix>\n </ax-conversation-info-bar>\n <ax-conversation-message-list class=\"ax-min-h-0 ax-flex-1 ax-overflow-hidden\">\n <div ax-conversation-message-list-no-active class=\"ax-block\" style=\"width: min(95%, 50rem)\">\n <axm-chat-empty-assist-composer (conversationCreated)=\"onConversationSelected($event)\" />\n </div>\n <axm-chat-assist-composer-starter-prompts ax-conversation-message-list-empty />\n </ax-conversation-message-list>\n </div>\n }\n </axp-page-content>\n\n <axp-page-footer class=\"ax-block\">\n <ax-conversation-composer></ax-conversation-composer>\n </axp-page-footer>\n</axp-page-layout>", styles: [":host ::ng-deep #axp-page-footer-container{padding:0!important}:host ::ng-deep .date-separator{z-index:50!important}:host ::ng-deep axp-layout-header{padding:0!important}\n"], dependencies: [{ kind: "directive", type: AXConversationContainerDirective, selector: "[axConversationContainer]" }, { kind: "component", type: AXSidebarComponent, selector: "ax-conversation-sidebar", outputs: ["conversationSelected"] }, { kind: "component", type: AXInfoBarComponent, selector: "ax-conversation-info-bar", outputs: ["avatarClick", "searchClick", "searchQuery", "menuItemAction"] }, { kind: "component", type: AXMessageListComponent, selector: "ax-conversation-message-list", inputs: ["avatarTemplate"], outputs: ["messageAction"] }, { kind: "component", type: AXComposerComponent, selector: "ax-conversation-composer", outputs: ["messageSent", "emojiClick", "attachClick", "voiceClick"] }, { kind: "component", type: AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i2$1.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "component", type: AXPPageLayoutComponent, selector: "axp-page-layout" }, { kind: "component", type: AXPThemeLayoutBlockComponent, selector: " axp-page-content, axp-page-footer-container, axp-page-footer, axp-page-header, axp-page-header-container, axp-page-toolbar, axp-layout-content, axp-layout-page-content, axp-layout-sections, axp-layout-body, axp-layout-page-body, axp-layout-prefix, axp-layout-suffix, axp-layout-title-bar, axp-layout-title, axp-layout-title-actions, axp-layout-nav-button, axp-layout-description, axp-layout-breadcrumbs, axp-layout-list-action, " }, { kind: "component", type: AXPThemeLayoutStartSideComponent, selector: "axp-layout-page-start-side, axp-layout-start-side" }, { kind: "component", type: AXMChatSidebarNewActionsComponent, selector: "axm-chat-sidebar-new-actions", outputs: ["conversationCreated"] }, { kind: "component", type: AXMChatEmptyAssistComposerComponent, selector: "axm-chat-empty-assist-composer", outputs: ["conversationCreated"] }, { kind: "component", type: AXMChatAssistComposerStarterPromptsComponent, selector: "axm-chat-assist-composer-starter-prompts" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2673
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXMChatComponent, isStandalone: true, selector: "axm-chat", host: { listeners: { "keydown.escape": "onContainerEscape()" }, properties: { "tabindex": "\"-1\"" } }, usesInheritance: true, ngImport: i0, template: "<axp-page-layout #container axConversationContainer>\n <!-- Sidebar: Always visible on desktop, visible on mobile only when no conversation is selected -->\n\n <axp-layout-start-side class=\"ax-border-e ax-lightest-surface ax-h-full\">\n <axp-layout-content class=\"ax-flex ax-flex-col ax-min-h-0 ax-max-w-80\">\n <div class=\"ax-h-full ax-flex ax-flex-col ax-shrink-0\">\n <ax-conversation-sidebar (conversationSelected)=\"onConversationSelected($event.id)\" class=\"ax-group\">\n <ax-suffix>\n <div class=\"ax-flex ax-h-14 ax-shrink-0 ax-items-center ax-justify-end ax-overflow-hidden\">\n <axm-chat-sidebar-new-actions\n class=\"group-hover:!ax-translate-y-0 !ax-translate-y-36 ax-transition-transform ax-duration-200\"\n (conversationCreated)=\"onConversationSelected($event)\"\n />\n </div>\n </ax-suffix>\n </ax-conversation-sidebar>\n </div>\n </axp-layout-content>\n </axp-layout-start-side>\n\n <!-- Chat content: Always visible on desktop, visible on mobile only when a conversation is selected -->\n\n <axp-page-content class=\"ax-h-full ax-overflow-hidden !ax-p-0 ax-flex ax-min-h-0 ax-flex-col\">\n @if (showChatList()) {\n <ax-conversation-sidebar (conversationSelected)=\"onConversationSelected($event.id)\" class=\"ax-group\">\n <ax-suffix>\n <div class=\"ax-flex ax-h-14 ax-shrink-0 ax-items-center ax-justify-end ax-overflow-hidden\">\n <axm-chat-sidebar-new-actions\n class=\"group-hover:!ax-translate-y-0 !ax-translate-y-36 ax-transition-transform ax-duration-200\"\n (conversationCreated)=\"onConversationSelected($event)\"\n />\n </div>\n </ax-suffix>\n </ax-conversation-sidebar>\n } @else {\n <div class=\"ax-flex ax-h-full ax-min-h-0 ax-flex-1 ax-flex-col\">\n <ax-conversation-info-bar class=\"ax-shadow-md\">\n <ax-prefix>\n <!-- Back button visible only on mobile -->\n @if (deviceService.isMobileDevice()) {\n <ax-button look=\"blank\" (onClick)=\"openChatList()\">\n <ax-icon icon=\"fa-light fa-bars\"></ax-icon>\n </ax-button>\n } @else {\n <ax-button class=\"ax-rounded-full\" look=\"blank\" (onClick)=\"onContainerEscape()\" aria-label=\"Close Chat\">\n <ax-icon icon=\"fa-light fa-xmark ax-text-xl\"></ax-icon>\n </ax-button>\n }\n </ax-prefix>\n </ax-conversation-info-bar>\n <ax-conversation-message-list class=\"ax-min-h-0 ax-flex-1 ax-overflow-hidden\" style=\"direction: ltr\">\n <div ax-conversation-message-list-no-active class=\"ax-block\" style=\"width: min(95%, 50rem)\">\n <axm-chat-empty-assist-composer (conversationCreated)=\"onConversationSelected($event)\" />\n </div>\n <axm-chat-assist-composer-starter-prompts ax-conversation-message-list-empty />\n </ax-conversation-message-list>\n </div>\n }\n </axp-page-content>\n\n <axp-page-footer class=\"ax-block\">\n <ax-conversation-composer></ax-conversation-composer>\n </axp-page-footer>\n</axp-page-layout>\n", styles: [":host ::ng-deep #axp-page-footer-container{padding:0!important}:host ::ng-deep .date-separator{z-index:50!important}:host ::ng-deep axp-layout-header{padding:0!important}\n"], dependencies: [{ kind: "directive", type: AXConversationContainerDirective, selector: "[axConversationContainer]" }, { kind: "component", type: AXSidebarComponent, selector: "ax-conversation-sidebar", outputs: ["conversationSelected"] }, { kind: "component", type: AXInfoBarComponent, selector: "ax-conversation-info-bar", outputs: ["avatarClick", "searchClick", "searchQuery", "menuItemAction"] }, { kind: "component", type: AXMessageListComponent, selector: "ax-conversation-message-list", inputs: ["avatarTemplate"], outputs: ["messageAction"] }, { kind: "component", type: AXComposerComponent, selector: "ax-conversation-composer", outputs: ["messageSent", "emojiClick", "attachClick", "voiceClick"] }, { kind: "component", type: AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i2$1.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "component", type: AXPPageLayoutComponent, selector: "axp-page-layout" }, { kind: "component", type: AXPThemeLayoutBlockComponent, selector: " axp-page-content, axp-page-footer-container, axp-page-footer, axp-page-header, axp-page-header-container, axp-page-toolbar, axp-layout-content, axp-layout-page-content, axp-layout-sections, axp-layout-body, axp-layout-page-body, axp-layout-prefix, axp-layout-suffix, axp-layout-title-bar, axp-layout-title, axp-layout-title-actions, axp-layout-nav-button, axp-layout-description, axp-layout-breadcrumbs, axp-layout-list-action, " }, { kind: "component", type: AXPThemeLayoutStartSideComponent, selector: "axp-layout-page-start-side, axp-layout-start-side" }, { kind: "component", type: AXMChatSidebarNewActionsComponent, selector: "axm-chat-sidebar-new-actions", outputs: ["conversationCreated"] }, { kind: "component", type: AXMChatEmptyAssistComposerComponent, selector: "axm-chat-empty-assist-composer", outputs: ["conversationCreated"] }, { kind: "component", type: AXMChatAssistComposerStarterPromptsComponent, selector: "axm-chat-assist-composer-starter-prompts" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3279
2674
  }
3280
2675
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMChatComponent, decorators: [{
3281
2676
  type: Component,
@@ -3297,7 +2692,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
3297
2692
  ], host: {
3298
2693
  '(keydown.escape)': 'onContainerEscape()',
3299
2694
  '[tabindex]': '"-1"',
3300
- }, template: "<axp-page-layout #container axConversationContainer>\n <!-- Sidebar: Always visible on desktop, visible on mobile only when no conversation is selected -->\n\n <axp-layout-start-side class=\"ax-border-e ax-lightest-surface ax-h-full\">\n <axp-layout-content class=\"ax-flex ax-flex-col ax-min-h-0 ax-max-w-80\">\n <div class=\"ax-h-full ax-flex ax-flex-col ax-shrink-0\">\n <ax-conversation-sidebar (conversationSelected)=\"onConversationSelected($event.id)\" class=\"ax-group\">\n <ax-suffix>\n <div class=\"ax-flex ax-h-14 ax-shrink-0 ax-items-center ax-justify-end ax-overflow-hidden\">\n <axm-chat-sidebar-new-actions\n class=\"group-hover:!ax-translate-y-0 !ax-translate-y-36 ax-transition-transform ax-duration-200\"\n (conversationCreated)=\"onConversationSelected($event)\" />\n </div>\n </ax-suffix>\n </ax-conversation-sidebar>\n </div>\n </axp-layout-content>\n </axp-layout-start-side>\n\n <!-- Chat content: Always visible on desktop, visible on mobile only when a conversation is selected -->\n\n <axp-page-content class=\"ax-h-full ax-overflow-hidden !ax-p-0 ax-flex ax-min-h-0 ax-flex-col\">\n @if (showChatList()) {\n <ax-conversation-sidebar (conversationSelected)=\"onConversationSelected($event.id)\" class=\"ax-group\">\n <ax-suffix>\n <div class=\"ax-flex ax-h-14 ax-shrink-0 ax-items-center ax-justify-end ax-overflow-hidden\">\n <axm-chat-sidebar-new-actions\n class=\"group-hover:!ax-translate-y-0 !ax-translate-y-36 ax-transition-transform ax-duration-200\"\n (conversationCreated)=\"onConversationSelected($event)\" />\n </div>\n </ax-suffix>\n </ax-conversation-sidebar>\n } @else {\n <div class=\"ax-flex ax-h-full ax-min-h-0 ax-flex-1 ax-flex-col\">\n <ax-conversation-info-bar class=\"ax-shadow-md\">\n <ax-prefix>\n <!-- Back button visible only on mobile -->\n @if (deviceService.isMobileDevice()) {\n <ax-button look=\"blank\" (onClick)=\"openChatList()\">\n <ax-icon icon=\"fa-light fa-bars\"></ax-icon>\n </ax-button>\n } @else {\n <ax-button class=\"ax-rounded-full\" look=\"blank\" (onClick)=\"onContainerEscape()\" aria-label=\"Close Chat\">\n <ax-icon icon=\"fa-light fa-xmark ax-text-xl\"></ax-icon>\n </ax-button>\n }\n </ax-prefix>\n </ax-conversation-info-bar>\n <ax-conversation-message-list class=\"ax-min-h-0 ax-flex-1 ax-overflow-hidden\">\n <div ax-conversation-message-list-no-active class=\"ax-block\" style=\"width: min(95%, 50rem)\">\n <axm-chat-empty-assist-composer (conversationCreated)=\"onConversationSelected($event)\" />\n </div>\n <axm-chat-assist-composer-starter-prompts ax-conversation-message-list-empty />\n </ax-conversation-message-list>\n </div>\n }\n </axp-page-content>\n\n <axp-page-footer class=\"ax-block\">\n <ax-conversation-composer></ax-conversation-composer>\n </axp-page-footer>\n</axp-page-layout>", styles: [":host ::ng-deep #axp-page-footer-container{padding:0!important}:host ::ng-deep .date-separator{z-index:50!important}:host ::ng-deep axp-layout-header{padding:0!important}\n"] }]
2695
+ }, template: "<axp-page-layout #container axConversationContainer>\n <!-- Sidebar: Always visible on desktop, visible on mobile only when no conversation is selected -->\n\n <axp-layout-start-side class=\"ax-border-e ax-lightest-surface ax-h-full\">\n <axp-layout-content class=\"ax-flex ax-flex-col ax-min-h-0 ax-max-w-80\">\n <div class=\"ax-h-full ax-flex ax-flex-col ax-shrink-0\">\n <ax-conversation-sidebar (conversationSelected)=\"onConversationSelected($event.id)\" class=\"ax-group\">\n <ax-suffix>\n <div class=\"ax-flex ax-h-14 ax-shrink-0 ax-items-center ax-justify-end ax-overflow-hidden\">\n <axm-chat-sidebar-new-actions\n class=\"group-hover:!ax-translate-y-0 !ax-translate-y-36 ax-transition-transform ax-duration-200\"\n (conversationCreated)=\"onConversationSelected($event)\"\n />\n </div>\n </ax-suffix>\n </ax-conversation-sidebar>\n </div>\n </axp-layout-content>\n </axp-layout-start-side>\n\n <!-- Chat content: Always visible on desktop, visible on mobile only when a conversation is selected -->\n\n <axp-page-content class=\"ax-h-full ax-overflow-hidden !ax-p-0 ax-flex ax-min-h-0 ax-flex-col\">\n @if (showChatList()) {\n <ax-conversation-sidebar (conversationSelected)=\"onConversationSelected($event.id)\" class=\"ax-group\">\n <ax-suffix>\n <div class=\"ax-flex ax-h-14 ax-shrink-0 ax-items-center ax-justify-end ax-overflow-hidden\">\n <axm-chat-sidebar-new-actions\n class=\"group-hover:!ax-translate-y-0 !ax-translate-y-36 ax-transition-transform ax-duration-200\"\n (conversationCreated)=\"onConversationSelected($event)\"\n />\n </div>\n </ax-suffix>\n </ax-conversation-sidebar>\n } @else {\n <div class=\"ax-flex ax-h-full ax-min-h-0 ax-flex-1 ax-flex-col\">\n <ax-conversation-info-bar class=\"ax-shadow-md\">\n <ax-prefix>\n <!-- Back button visible only on mobile -->\n @if (deviceService.isMobileDevice()) {\n <ax-button look=\"blank\" (onClick)=\"openChatList()\">\n <ax-icon icon=\"fa-light fa-bars\"></ax-icon>\n </ax-button>\n } @else {\n <ax-button class=\"ax-rounded-full\" look=\"blank\" (onClick)=\"onContainerEscape()\" aria-label=\"Close Chat\">\n <ax-icon icon=\"fa-light fa-xmark ax-text-xl\"></ax-icon>\n </ax-button>\n }\n </ax-prefix>\n </ax-conversation-info-bar>\n <ax-conversation-message-list class=\"ax-min-h-0 ax-flex-1 ax-overflow-hidden\" style=\"direction: ltr\">\n <div ax-conversation-message-list-no-active class=\"ax-block\" style=\"width: min(95%, 50rem)\">\n <axm-chat-empty-assist-composer (conversationCreated)=\"onConversationSelected($event)\" />\n </div>\n <axm-chat-assist-composer-starter-prompts ax-conversation-message-list-empty />\n </ax-conversation-message-list>\n </div>\n }\n </axp-page-content>\n\n <axp-page-footer class=\"ax-block\">\n <ax-conversation-composer></ax-conversation-composer>\n </axp-page-footer>\n</axp-page-layout>\n", styles: [":host ::ng-deep #axp-page-footer-container{padding:0!important}:host ::ng-deep .date-separator{z-index:50!important}:host ::ng-deep axp-layout-header{padding:0!important}\n"] }]
3301
2696
  }] });
3302
2697
 
3303
2698
  var chat_component = /*#__PURE__*/Object.freeze({
@@ -4786,40 +4181,6 @@ const AXMCommentPopupWorkflow = {
4786
4181
  },
4787
4182
  };
4788
4183
 
4789
- class AXMChatBadgeProviderSimple {
4790
- constructor() {
4791
- this.chatService = inject(AXMChatManagementService);
4792
- this.realtime = inject(AXMChatRealtimeService);
4793
- this.key = 'badge-chat';
4794
- this.count = signal(0, ...(ngDevMode ? [{ debugName: "count" }] : /* istanbul ignore next */ []));
4795
- this._events = toSignal(merge(this.realtime.room$, this.realtime.message$).pipe(auditTime(150)), {
4796
- initialValue: null,
4797
- });
4798
- // Initial load
4799
- this.refresh();
4800
- // Refresh on any room/message event
4801
- effect(async () => {
4802
- // track events
4803
- this._events();
4804
- try {
4805
- await this.refresh();
4806
- }
4807
- catch (err) {
4808
- console.error('AXMChatBadgeProviderSimple: refresh failed', err);
4809
- }
4810
- });
4811
- }
4812
- async refresh() {
4813
- const response = await this.chatService.listRooms();
4814
- this.count.set(response.items.filter((i) => i.unreadCount > 0).length);
4815
- }
4816
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMChatBadgeProviderSimple, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4817
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMChatBadgeProviderSimple }); }
4818
- }
4819
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMChatBadgeProviderSimple, decorators: [{
4820
- type: Injectable
4821
- }], ctorParameters: () => [] });
4822
-
4823
4184
  //#region ---- Imports ----
4824
4185
  //#endregion
4825
4186
  //#region ---- Message classification ----
@@ -6234,7 +5595,7 @@ async function axmOpenAssistDelegatedAgentDetailDialog(options) {
6234
5595
  options.translationService.translateAsync('@conversation:chat.assist-renderer.delegated-agent.dialog-title-suffix'),
6235
5596
  options.translationService.translateAsync('@conversation:chat.assist-renderer.delegated-agent.transcript-missing'),
6236
5597
  ]);
6237
- const comp = (await import('./acorex-modules-conversation-assist-delegated-agent-detail-popup.component-Be58gcns.mjs'))
5598
+ const comp = (await import('./acorex-modules-conversation-assist-delegated-agent-detail-popup.component-BAgBuxlz.mjs'))
6238
5599
  .AXMAssistDelegatedAgentDetailPopupComponent;
6239
5600
  const data = {
6240
5601
  messages: entry?.messages ?? [],
@@ -7194,13 +6555,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
7194
6555
  changeDetection: ChangeDetectionStrategy.OnPush,
7195
6556
  }]
7196
6557
  }], propDecorators: { item: [{ type: i0.Input, args: [{ isSignal: true, alias: "item", required: false }] }], execute: [{ type: i0.Output, args: ["execute"] }] } });
7197
-
7198
- //#region ---- Imports ----
7199
- //#endregion
7200
- //#region ---- Chat Notification Provider ----
7201
- /**
7202
- * Provides notification handling and content for Chat.
7203
- */
7204
6558
  class AXMChatNotificationProvider {
7205
6559
  constructor(injector) {
7206
6560
  this.injector = injector;
@@ -7213,7 +6567,7 @@ class AXMChatNotificationProvider {
7213
6567
  }
7214
6568
  async execute(command, item) {
7215
6569
  const router = this.injector.get(Router);
7216
- const chatService = this.injector.get(AXMChatManagementService);
6570
+ const chatService = this.injector.get(AXConversationService);
7217
6571
  const activatedRoute = this.injector.get(ActivatedRoute);
7218
6572
  const roomId = item.data?.['roomId'];
7219
6573
  if (!roomId) {
@@ -7223,14 +6577,14 @@ class AXMChatNotificationProvider {
7223
6577
  const app = activatedRoute.snapshot.firstChild?.paramMap.get('app') || 'platform';
7224
6578
  switch (command.name) {
7225
6579
  case 'mark-as-seen':
7226
- await chatService.markRoomSeen(roomId);
6580
+ await chatService.markAsRead(roomId);
7227
6581
  break;
7228
6582
  case 'go-to-chat':
7229
- await chatService.markRoomSeen(roomId);
6583
+ await chatService.markAsRead(roomId);
7230
6584
  router.navigate([app, 'chat', roomId]);
7231
6585
  break;
7232
6586
  case 'click':
7233
- await chatService.markRoomSeen(roomId);
6587
+ await chatService.markAsRead(roomId);
7234
6588
  router.navigate([app, 'chat', roomId]);
7235
6589
  break;
7236
6590
  default:
@@ -7251,7 +6605,6 @@ const AXM_CHAT_NOTIFICATION_PROVIDERS = [
7251
6605
  multi: true,
7252
6606
  },
7253
6607
  ];
7254
- //#endregion
7255
6608
 
7256
6609
  //#region ---- Imports ----
7257
6610
  //#endregion
@@ -7309,7 +6662,7 @@ class AXMCommentsPageComponentProvider {
7309
6662
  return [
7310
6663
  {
7311
6664
  key: COMMENTS_PAGE_COMPONENT_KEY,
7312
- loader: () => import('./acorex-modules-conversation-comments-page.component-3XBLeMW8.mjs').then((m) => m.AXMCommentsPageComponent),
6665
+ loader: () => import('./acorex-modules-conversation-comments-page.component-BrwP9l7M.mjs').then((m) => m.AXMCommentsPageComponent),
7313
6666
  },
7314
6667
  ];
7315
6668
  }
@@ -7404,15 +6757,6 @@ class AXMConversationModule {
7404
6757
  // Modules
7405
6758
  RouterModule] }); }
7406
6759
  static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMConversationModule, providers: [
7407
- // Chat and Comment Services
7408
- {
7409
- provide: AXMChatService,
7410
- useClass: AXMChatServiceImpl,
7411
- },
7412
- {
7413
- provide: AXMChatRealtimeService,
7414
- useClass: AXMChatRealtimeServiceImpl,
7415
- },
7416
6760
  {
7417
6761
  provide: AXMCommentService,
7418
6762
  useClass: AXMCommentServiceImpl,
@@ -7488,11 +6832,11 @@ class AXMConversationModule {
7488
6832
  provideCommandSetups([
7489
6833
  {
7490
6834
  key: CONVERSATION_START_ASSIST_CHAT_COMMAND,
7491
- command: () => import('./acorex-modules-conversation-start-assist-chat.command-CyoncQB1.mjs').then((m) => m.AXMConversationStartAssistChatCommand),
6835
+ command: () => import('./acorex-modules-conversation-start-assist-chat.command-BUOGUMl0.mjs').then((m) => m.AXMConversationStartAssistChatCommand),
7492
6836
  },
7493
6837
  {
7494
6838
  key: CONVERSATION_SEND_ASSIST_CHAT_MESSAGE_COMMAND,
7495
- command: () => import('./acorex-modules-conversation-send-assist-chat-message.command-CSu-lJuu.mjs').then((m) => m.AXMConversationSendAssistChatMessageCommand),
6839
+ command: () => import('./acorex-modules-conversation-send-assist-chat-message.command-BzKawEoN.mjs').then((m) => m.AXMConversationSendAssistChatMessageCommand),
7496
6840
  },
7497
6841
  ]),
7498
6842
  ], imports: [AXPWidgetCoreModule,
@@ -7535,15 +6879,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
7535
6879
  RouterModule,
7536
6880
  ],
7537
6881
  providers: [
7538
- // Chat and Comment Services
7539
- {
7540
- provide: AXMChatService,
7541
- useClass: AXMChatServiceImpl,
7542
- },
7543
- {
7544
- provide: AXMChatRealtimeService,
7545
- useClass: AXMChatRealtimeServiceImpl,
7546
- },
7547
6882
  {
7548
6883
  provide: AXMCommentService,
7549
6884
  useClass: AXMCommentServiceImpl,
@@ -7619,11 +6954,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
7619
6954
  provideCommandSetups([
7620
6955
  {
7621
6956
  key: CONVERSATION_START_ASSIST_CHAT_COMMAND,
7622
- command: () => import('./acorex-modules-conversation-start-assist-chat.command-CyoncQB1.mjs').then((m) => m.AXMConversationStartAssistChatCommand),
6957
+ command: () => import('./acorex-modules-conversation-start-assist-chat.command-BUOGUMl0.mjs').then((m) => m.AXMConversationStartAssistChatCommand),
7623
6958
  },
7624
6959
  {
7625
6960
  key: CONVERSATION_SEND_ASSIST_CHAT_MESSAGE_COMMAND,
7626
- command: () => import('./acorex-modules-conversation-send-assist-chat-message.command-CSu-lJuu.mjs').then((m) => m.AXMConversationSendAssistChatMessageCommand),
6961
+ command: () => import('./acorex-modules-conversation-send-assist-chat-message.command-BzKawEoN.mjs').then((m) => m.AXMConversationSendAssistChatMessageCommand),
7627
6962
  },
7628
6963
  ]),
7629
6964
  ],
@@ -7634,5 +6969,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
7634
6969
  * Generated bundle index. Do not edit.
7635
6970
  */
7636
6971
 
7637
- export { axmReadAssistAiTranscript as $, AXMChatAssistLauncherService as A, AXMCommentWidgetViewComponent as B, CONVERSATION_SEND_ASSIST_CHAT_MESSAGE_COMMAND as C, AXMConversationModule as D, AXMConversationTabEntityModule as E, AXMConversationTabService as F, AXMConversationTabServiceImpl as G, AXMMessageEntityModule as H, AXMMessageService as I, AXMMessageServiceImpl as J, AXMPermissionsKeys as K, AXMRoomEntityModule as L, AXMRoomService as M, AXMRoomServiceImpl as N, AXM_ASSIST_TRANSCRIPT_LINE_PAYLOAD_TYPE as O, AXPCommentWidget as P, COMMENTS_PAGE_COMPONENT_KEY as Q, RootConfig as R, axmAssistFollowUpItemsFromUnknown as S, axmAssistLastTranscriptLine as T, axmAssistUserFacingPayloadLine as U, axmAssistUserVisibleItemsForLine as V, axmBuildAssistTranscriptLinePayload as W, axmIsAssistPeerParticipant as X, axmNormalizeAssistTranscriptForChatUi as Y, axmNormalizeAssistTranscriptLineResponses as Z, axmParseAssistTranscriptLinePayload as _, AXMCommentComponent as a, axmReadAssistAiTranscriptRaw as a0, commentsPlugin as a1, messageFactory as a2, roomFactory as a3, tabFactory as a4, axmAssistSegmentDirection as b, axmParseAssistTranscriptTextEnvelope as c, axmAssistWidgetNodeFromUnknown as d, axmSyntheticEmbedMessage as e, AXMNodeMessageRendererComponent as f, AXMAssistBotImageLineComponent as g, AXMAssistSuggestionChipsComponent as h, AXMChatComponent as i, AXMChatConversationApi as j, AXMChatManagementService as k, AXMChatMessageApi as l, AXMChatRealtimeApi as m, AXMChatRealtimeService as n, AXMChatRealtimeServiceImpl as o, AXMChatService as p, AXMChatServiceImpl as q, AXMChatUserApi as r, AXMCommentManagementService as s, AXMCommentPopupComponent as t, AXMCommentPopupStartAction as u, AXMCommentPopupWorkflow as v, AXMCommentRealtimeService as w, AXMCommentRealtimeServiceImpl as x, AXMCommentService as y, AXMCommentServiceImpl as z };
7638
- //# sourceMappingURL=acorex-modules-conversation-acorex-modules-conversation-UNhA-qi5.mjs.map
6972
+ export { tabFactory as $, AXMChatAssistLauncherService as A, AXMMessageEntityModule as B, CONVERSATION_SEND_ASSIST_CHAT_MESSAGE_COMMAND as C, AXMMessageService as D, AXMMessageServiceImpl as E, AXMPermissionsKeys as F, AXMRoomEntityModule as G, AXMRoomService as H, AXMRoomServiceImpl as I, AXM_ASSIST_TRANSCRIPT_LINE_PAYLOAD_TYPE as J, AXPCommentWidget as K, COMMENTS_PAGE_COMPONENT_KEY as L, axmAssistFollowUpItemsFromUnknown as M, axmAssistLastTranscriptLine as N, axmAssistUserFacingPayloadLine as O, axmAssistUserVisibleItemsForLine as P, axmBuildAssistTranscriptLinePayload as Q, RootConfig as R, axmIsAssistPeerParticipant as S, axmNormalizeAssistTranscriptForChatUi as T, axmNormalizeAssistTranscriptLineResponses as U, axmParseAssistTranscriptLinePayload as V, axmReadAssistAiTranscript as W, axmReadAssistAiTranscriptRaw as X, commentsPlugin as Y, messageFactory as Z, roomFactory as _, AXMCommentComponent as a, axmAssistSegmentDirection as b, axmParseAssistTranscriptTextEnvelope as c, axmAssistWidgetNodeFromUnknown as d, axmSyntheticEmbedMessage as e, AXMNodeMessageRendererComponent as f, AXMAssistBotImageLineComponent as g, AXMAssistSuggestionChipsComponent as h, AXMChatComponent as i, AXMChatConversationApi as j, AXMChatMessageApi as k, AXMChatRealtimeApi as l, AXMChatUserApi as m, AXMCommentManagementService as n, AXMCommentPopupComponent as o, AXMCommentPopupStartAction as p, AXMCommentPopupWorkflow as q, AXMCommentRealtimeService as r, AXMCommentRealtimeServiceImpl as s, AXMCommentService as t, AXMCommentServiceImpl as u, AXMCommentWidgetViewComponent as v, AXMConversationModule as w, AXMConversationTabEntityModule as x, AXMConversationTabService as y, AXMConversationTabServiceImpl as z };
6973
+ //# sourceMappingURL=acorex-modules-conversation-acorex-modules-conversation-DlteA_jC.mjs.map