@memberjunction/ng-conversations 5.35.0 → 5.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +62 -2
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.js +300 -24
- package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
- package/dist/lib/components/dialogs/rating-dialog.component.d.ts +31 -0
- package/dist/lib/components/dialogs/rating-dialog.component.d.ts.map +1 -0
- package/dist/lib/components/dialogs/rating-dialog.component.js +290 -0
- package/dist/lib/components/dialogs/rating-dialog.component.js.map +1 -0
- package/dist/lib/components/mention/mention-editor.component.d.ts +1 -1
- package/dist/lib/components/mention/mention-editor.component.d.ts.map +1 -1
- package/dist/lib/components/mention/mention-editor.component.js +1 -0
- package/dist/lib/components/mention/mention-editor.component.js.map +1 -1
- package/dist/lib/components/message/conversation-message-rating.component.d.ts +43 -18
- package/dist/lib/components/message/conversation-message-rating.component.d.ts.map +1 -1
- package/dist/lib/components/message/conversation-message-rating.component.js +235 -193
- package/dist/lib/components/message/conversation-message-rating.component.js.map +1 -1
- package/dist/lib/components/message/message-input-box.component.d.ts +1 -1
- package/dist/lib/components/message/message-input-box.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-input-box.component.js +1 -1
- package/dist/lib/components/message/message-input-box.component.js.map +1 -1
- package/dist/lib/components/message/message-input.component.d.ts +7 -1
- package/dist/lib/components/message/message-input.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-input.component.js +28 -3
- package/dist/lib/components/message/message-input.component.js.map +1 -1
- package/dist/lib/components/message/message-item.component.js +20 -20
- package/dist/lib/components/message/message-item.component.js.map +1 -1
- package/dist/lib/components/overlay/chat-overlay.component.d.ts +73 -5
- package/dist/lib/components/overlay/chat-overlay.component.d.ts.map +1 -1
- package/dist/lib/components/overlay/chat-overlay.component.js +202 -37
- package/dist/lib/components/overlay/chat-overlay.component.js.map +1 -1
- package/dist/lib/conversations.module.d.ts +24 -23
- package/dist/lib/conversations.module.d.ts.map +1 -1
- package/dist/lib/conversations.module.js +4 -0
- package/dist/lib/conversations.module.js.map +1 -1
- package/dist/lib/services/data-cache.service.d.ts.map +1 -1
- package/dist/lib/services/data-cache.service.js +0 -1
- package/dist/lib/services/data-cache.service.js.map +1 -1
- package/dist/lib/services/dialog.service.d.ts +24 -0
- package/dist/lib/services/dialog.service.d.ts.map +1 -1
- package/dist/lib/services/dialog.service.js +45 -0
- package/dist/lib/services/dialog.service.js.map +1 -1
- package/package.json +22 -22
|
@@ -1,255 +1,297 @@
|
|
|
1
1
|
import { Component, Input } from '@angular/core';
|
|
2
2
|
import { BaseAngularComponent } from '@memberjunction/ng-base-types';
|
|
3
3
|
import { RunView } from '@memberjunction/core';
|
|
4
|
-
import {
|
|
4
|
+
import { UserInfoEngine } from '@memberjunction/core-entities';
|
|
5
5
|
import * as i0 from "@angular/core";
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
import * as i1 from "../../services/dialog.service";
|
|
7
|
+
function ConversationMessageRatingComponent_Conditional_2_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
8
|
+
i0.ɵɵelement(0, "i", 5);
|
|
9
|
+
i0.ɵɵelementStart(1, "span", 6);
|
|
8
10
|
i0.ɵɵtext(2);
|
|
9
11
|
i0.ɵɵelementEnd();
|
|
10
|
-
|
|
11
|
-
i0.ɵɵ
|
|
12
|
+
} if (rf & 2) {
|
|
13
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
14
|
+
i0.ɵɵadvance(2);
|
|
15
|
+
i0.ɵɵtextInterpolate1("My rating: ", ctx_r1.currentUserRating, "/10");
|
|
16
|
+
} }
|
|
17
|
+
function ConversationMessageRatingComponent_Conditional_2_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
18
|
+
i0.ɵɵelement(0, "i", 7);
|
|
19
|
+
i0.ɵɵelementStart(1, "span");
|
|
20
|
+
i0.ɵɵtext(2, "Rate response");
|
|
21
|
+
i0.ɵɵelementEnd();
|
|
22
|
+
} }
|
|
23
|
+
function ConversationMessageRatingComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
24
|
+
const _r1 = i0.ɵɵgetCurrentView();
|
|
25
|
+
i0.ɵɵelementStart(0, "button", 4);
|
|
26
|
+
i0.ɵɵlistener("click", function ConversationMessageRatingComponent_Conditional_2_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OpenRatingDialog()); });
|
|
27
|
+
i0.ɵɵconditionalCreate(1, ConversationMessageRatingComponent_Conditional_2_Conditional_1_Template, 3, 1)(2, ConversationMessageRatingComponent_Conditional_2_Conditional_2_Template, 3, 0);
|
|
12
28
|
i0.ɵɵelementEnd();
|
|
13
|
-
i0.ɵɵelementStart(5, "span", 7);
|
|
14
|
-
i0.ɵɵtext(6);
|
|
15
|
-
i0.ɵɵelementEnd()();
|
|
16
29
|
} if (rf & 2) {
|
|
17
|
-
const
|
|
18
|
-
i0.ɵɵ
|
|
19
|
-
i0.ɵɵ
|
|
20
|
-
i0.ɵɵclassProp("has-votes", ctx_r0.thumbsUpCount > 0);
|
|
21
|
-
i0.ɵɵadvance();
|
|
22
|
-
i0.ɵɵtextInterpolate1(" \uD83D\uDC4D ", ctx_r0.thumbsUpCount, " ");
|
|
30
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
31
|
+
i0.ɵɵclassProp("has-rated", ctx_r1.currentUserRating != null);
|
|
32
|
+
i0.ɵɵproperty("disabled", ctx_r1.isSaving)("title", ctx_r1.currentUserRating != null ? "Edit your rating" : "Rate this response");
|
|
23
33
|
i0.ɵɵadvance();
|
|
24
|
-
i0.ɵɵ
|
|
25
|
-
i0.ɵɵadvance();
|
|
26
|
-
i0.ɵɵtextInterpolate1(" \uD83D\uDC4E ", ctx_r0.thumbsDownCount, " ");
|
|
27
|
-
i0.ɵɵadvance(2);
|
|
28
|
-
i0.ɵɵtextInterpolate2("(", ctx_r0.totalRatings, " ", ctx_r0.totalRatings === 1 ? "rating" : "ratings", ")");
|
|
34
|
+
i0.ɵɵconditional(ctx_r1.currentUserRating != null ? 1 : 2);
|
|
29
35
|
} }
|
|
36
|
+
function ConversationMessageRatingComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
37
|
+
i0.ɵɵelementStart(0, "span", 3);
|
|
38
|
+
i0.ɵɵelement(1, "i", 8);
|
|
39
|
+
i0.ɵɵelementStart(2, "span");
|
|
40
|
+
i0.ɵɵtext(3);
|
|
41
|
+
i0.ɵɵelementEnd()();
|
|
42
|
+
} if (rf & 2) {
|
|
43
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
44
|
+
i0.ɵɵadvance(3);
|
|
45
|
+
i0.ɵɵtextInterpolate1("Rated ", ctx_r1.currentUserRating, "/10");
|
|
46
|
+
} }
|
|
47
|
+
const FEEDBACK_CONSENT_KEY = 'agent-feedback-share-consent';
|
|
48
|
+
const CONVERSATIONS_RESOURCE_TYPE_ID = '81D4BC3D-9FEB-EF11-B01A-286B35C04427';
|
|
49
|
+
const FEEDBACK_ROLE_IDS = [
|
|
50
|
+
'deafccec-6a37-ef11-86d4-000d3a4e707e', // Developer
|
|
51
|
+
'dfafccec-6a37-ef11-86d4-000d3a4e707e' // Integration
|
|
52
|
+
];
|
|
30
53
|
/**
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
54
|
+
* Single-rating-per-message rating UI for an AI conversation response.
|
|
55
|
+
*
|
|
56
|
+
* Storage model: the rating + free-form comment live directly on the
|
|
57
|
+
* ConversationDetail row, in `UserRating` (1-10, nullable) and `UserFeedback`
|
|
58
|
+
* (nvarchar(max), nullable). This matches MJ's own pattern on
|
|
59
|
+
* `__mj.ConversationDetail` and Skip's matching columns on
|
|
60
|
+
* `Skip.ConversationDetail`. The host app picks the entity via @Input.
|
|
34
61
|
*/
|
|
35
62
|
export class ConversationMessageRatingComponent extends BaseAngularComponent {
|
|
36
63
|
cdr;
|
|
64
|
+
dialogService;
|
|
37
65
|
conversationDetailId;
|
|
38
66
|
currentUser;
|
|
67
|
+
/**
|
|
68
|
+
* When false, the rating UI renders as a read-only badge instead of an editable
|
|
69
|
+
* button. Set by the parent (MessageItemComponent) to `false` when the current
|
|
70
|
+
* user is not the conversation owner — the rating storage is a single field on
|
|
71
|
+
* the ConversationDetail row, so only the owner is allowed to mutate it.
|
|
72
|
+
*/
|
|
73
|
+
canEdit = true;
|
|
74
|
+
/**
|
|
75
|
+
* Entity name to load/update for the rating. Defaults to MJ's
|
|
76
|
+
* `MJ: Conversation Details` (which has `UserRating`/`UserFeedback`).
|
|
77
|
+
* Skip-Brain hosts pass `'Conversation Details__Skip'`.
|
|
78
|
+
*/
|
|
79
|
+
ratingEntityName = 'MJ: Conversation Details';
|
|
80
|
+
/** Column on the entity that stores the 1-10 rating. */
|
|
81
|
+
ratingField = 'UserRating';
|
|
82
|
+
/** Column on the entity that stores the free-form feedback. */
|
|
83
|
+
ratingCommentField = 'UserFeedback';
|
|
84
|
+
/**
|
|
85
|
+
* Optional: legacy pre-loaded ratings array (no longer used by storage; kept
|
|
86
|
+
* to preserve the input shape used by existing call sites like
|
|
87
|
+
* MessageItemComponent).
|
|
88
|
+
*/
|
|
39
89
|
ratingsData;
|
|
40
|
-
thumbsUpCount = 0;
|
|
41
|
-
thumbsDownCount = 0;
|
|
42
|
-
totalRatings = 0;
|
|
43
90
|
currentUserRating = null;
|
|
91
|
+
currentUserComments = '';
|
|
44
92
|
isSaving = false;
|
|
45
|
-
|
|
46
|
-
currentUserRatingId = null;
|
|
47
|
-
get currentUserId() {
|
|
48
|
-
return this.currentUser?.ID || '';
|
|
49
|
-
}
|
|
50
|
-
constructor(cdr) {
|
|
93
|
+
constructor(cdr, dialogService) {
|
|
51
94
|
super();
|
|
52
95
|
this.cdr = cdr;
|
|
96
|
+
this.dialogService = dialogService;
|
|
53
97
|
}
|
|
54
98
|
async ngOnInit() {
|
|
55
|
-
|
|
56
|
-
|
|
99
|
+
await this.loadRating();
|
|
100
|
+
}
|
|
101
|
+
async OpenRatingDialog() {
|
|
102
|
+
if (this.isSaving)
|
|
103
|
+
return;
|
|
104
|
+
if (!this.canEdit)
|
|
105
|
+
return;
|
|
106
|
+
let consentAcknowledged = false;
|
|
107
|
+
try {
|
|
108
|
+
await UserInfoEngine.Instance.Config();
|
|
109
|
+
consentAcknowledged = UserInfoEngine.Instance.GetSetting(FEEDBACK_CONSENT_KEY) === 'true';
|
|
57
110
|
}
|
|
58
|
-
|
|
59
|
-
|
|
111
|
+
catch (e) {
|
|
112
|
+
console.warn('[Rating] Could not read consent flag, will require acknowledgement', e);
|
|
113
|
+
}
|
|
114
|
+
const result = await this.dialogService.rating({
|
|
115
|
+
title: this.currentUserRating != null ? 'Edit your rating' : 'Rate this response',
|
|
116
|
+
message: 'Rate the response on a 1-10 scale and (optionally) describe what was good or bad.',
|
|
117
|
+
initialRating: this.currentUserRating,
|
|
118
|
+
initialComments: this.currentUserComments,
|
|
119
|
+
okText: 'Submit',
|
|
120
|
+
requireConsent: !consentAcknowledged
|
|
121
|
+
});
|
|
122
|
+
if (result == null)
|
|
123
|
+
return;
|
|
124
|
+
const conversationID = await this.saveRating(result.rating, result.comments);
|
|
125
|
+
if (result.consentNewlyAcknowledged) {
|
|
126
|
+
try {
|
|
127
|
+
const saved = await UserInfoEngine.Instance.SetSetting(FEEDBACK_CONSENT_KEY, 'true');
|
|
128
|
+
if (!saved) {
|
|
129
|
+
console.error(`[Rating] Failed to persist consent acknowledgement under key "${FEEDBACK_CONSENT_KEY}" — ` +
|
|
130
|
+
`the dialog will re-prompt on next rating. Likely cause: the current user lacks ` +
|
|
131
|
+
`create/update permission on the "MJ: User Settings" entity.`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
catch (e) {
|
|
135
|
+
console.error('[Rating] Could not persist consent flag', e);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (conversationID) {
|
|
139
|
+
await this.grantConversationAccess(conversationID);
|
|
60
140
|
}
|
|
61
141
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
this.currentUserRatingId = mine ? mine.ID ?? null : null;
|
|
70
|
-
}
|
|
71
|
-
getRatingsTooltip() {
|
|
72
|
-
if (this.allRatings.length === 0)
|
|
73
|
-
return '';
|
|
74
|
-
const upUsers = this.allRatings
|
|
75
|
-
.filter(r => r.Rating != null && r.Rating >= 8)
|
|
76
|
-
.map(r => r.UserName || 'Unknown')
|
|
77
|
-
.join(', ');
|
|
78
|
-
const downUsers = this.allRatings
|
|
79
|
-
.filter(r => r.Rating != null && r.Rating <= 3)
|
|
80
|
-
.map(r => r.UserName || 'Unknown')
|
|
81
|
-
.join(', ');
|
|
82
|
-
const parts = [];
|
|
83
|
-
if (upUsers)
|
|
84
|
-
parts.push(`👍 ${upUsers}`);
|
|
85
|
-
if (downUsers)
|
|
86
|
-
parts.push(`👎 ${downUsers}`);
|
|
87
|
-
return parts.join('\n');
|
|
88
|
-
}
|
|
89
|
-
async RateThumbsUp() {
|
|
90
|
-
await this.saveRating(10);
|
|
91
|
-
}
|
|
92
|
-
async RateThumbsDown() {
|
|
93
|
-
await this.saveRating(1);
|
|
94
|
-
}
|
|
95
|
-
async loadRatings() {
|
|
142
|
+
/**
|
|
143
|
+
* Grants the Integrations and Developer roles View access to the parent
|
|
144
|
+
* Conversation via `MJ: Resource Permissions`. Idempotent — existing
|
|
145
|
+
* permissions for the same role are not duplicated. Best-effort; any error
|
|
146
|
+
* is logged but does not roll back the rating itself.
|
|
147
|
+
*/
|
|
148
|
+
async grantConversationAccess(conversationID) {
|
|
96
149
|
try {
|
|
97
|
-
const
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
150
|
+
const md = this.ProviderToUse;
|
|
151
|
+
const rv = new RunView();
|
|
152
|
+
const existing = await rv.RunView({
|
|
153
|
+
EntityName: 'MJ: Resource Permissions',
|
|
154
|
+
ExtraFilter: `ResourceTypeID='${CONVERSATIONS_RESOURCE_TYPE_ID}' AND ` +
|
|
155
|
+
`ResourceRecordID='${conversationID}' AND Type='Role' AND ` +
|
|
156
|
+
`RoleID IN ('${FEEDBACK_ROLE_IDS.join("','")}')`
|
|
102
157
|
});
|
|
103
|
-
|
|
104
|
-
|
|
158
|
+
const granted = new Set((existing.Results || []).map((r) => (r.RoleID || '').toLowerCase()));
|
|
159
|
+
for (const roleID of FEEDBACK_ROLE_IDS) {
|
|
160
|
+
if (granted.has(roleID.toLowerCase()))
|
|
161
|
+
continue;
|
|
162
|
+
const perm = await md.GetEntityObject('MJ: Resource Permissions');
|
|
163
|
+
perm.NewRecord();
|
|
164
|
+
perm.Set('ResourceTypeID', CONVERSATIONS_RESOURCE_TYPE_ID);
|
|
165
|
+
perm.Set('ResourceRecordID', conversationID);
|
|
166
|
+
perm.Set('Type', 'Role');
|
|
167
|
+
perm.Set('RoleID', roleID);
|
|
168
|
+
perm.Set('PermissionLevel', 'View');
|
|
169
|
+
perm.Set('Status', 'Approved');
|
|
170
|
+
const ok = await perm.Save();
|
|
171
|
+
if (!ok) {
|
|
172
|
+
console.warn('[Rating] Failed to create ResourcePermission for role', roleID, perm.LatestResult);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
catch (e) {
|
|
177
|
+
console.warn('[Rating] grantConversationAccess failed:', e);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
async loadRating() {
|
|
181
|
+
if (!this.conversationDetailId)
|
|
182
|
+
return;
|
|
183
|
+
try {
|
|
184
|
+
const md = this.ProviderToUse;
|
|
185
|
+
const entity = (await md.GetEntityObject(this.ratingEntityName));
|
|
186
|
+
const loaded = await entity.Load(this.conversationDetailId);
|
|
187
|
+
if (loaded) {
|
|
188
|
+
const rating = entity.Get(this.ratingField);
|
|
189
|
+
this.currentUserRating = rating != null ? Number(rating) : null;
|
|
190
|
+
this.currentUserComments = (entity.Get(this.ratingCommentField) ?? '');
|
|
105
191
|
this.cdr.detectChanges();
|
|
106
192
|
}
|
|
107
193
|
}
|
|
108
194
|
catch (error) {
|
|
109
|
-
|
|
195
|
+
// Silently swallow — message may not be persisted yet, or entity lookup failed.
|
|
196
|
+
console.warn('[ConversationMessageRating] Could not load existing rating:', error);
|
|
110
197
|
}
|
|
111
198
|
}
|
|
112
|
-
|
|
113
|
-
const wasThumbsUp = this.currentUserRating != null && this.currentUserRating >= 8;
|
|
114
|
-
const wasThumbsDown = this.currentUserRating != null && this.currentUserRating <= 3;
|
|
115
|
-
// Adjust counts when switching from an existing rating
|
|
116
|
-
if (wasThumbsUp)
|
|
117
|
-
this.thumbsUpCount--;
|
|
118
|
-
if (wasThumbsDown)
|
|
119
|
-
this.thumbsDownCount--;
|
|
120
|
-
if (!wasThumbsUp && !wasThumbsDown)
|
|
121
|
-
this.totalRatings++;
|
|
122
|
-
this.currentUserRating = rating;
|
|
123
|
-
if (rating >= 8)
|
|
124
|
-
this.thumbsUpCount++;
|
|
125
|
-
else
|
|
126
|
-
this.thumbsDownCount++;
|
|
127
|
-
}
|
|
128
|
-
async saveRating(rating) {
|
|
199
|
+
async saveRating(rating, comments) {
|
|
129
200
|
if (this.isSaving)
|
|
130
|
-
return;
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
201
|
+
return null;
|
|
202
|
+
if (rating < 1 || rating > 10)
|
|
203
|
+
return null;
|
|
204
|
+
if (!this.conversationDetailId)
|
|
205
|
+
return null;
|
|
135
206
|
const prevRating = this.currentUserRating;
|
|
136
|
-
const
|
|
137
|
-
const prevThumbsUp = this.thumbsUpCount;
|
|
138
|
-
const prevThumbsDown = this.thumbsDownCount;
|
|
139
|
-
const prevTotal = this.totalRatings;
|
|
140
|
-
// Optimistic update — UI reflects change instantly
|
|
207
|
+
const prevComments = this.currentUserComments;
|
|
141
208
|
this.isSaving = true;
|
|
142
|
-
this.
|
|
209
|
+
this.currentUserRating = rating;
|
|
210
|
+
this.currentUserComments = comments;
|
|
143
211
|
this.cdr.detectChanges();
|
|
144
212
|
try {
|
|
145
|
-
|
|
213
|
+
const md = this.ProviderToUse;
|
|
214
|
+
const entity = (await md.GetEntityObject(this.ratingEntityName));
|
|
215
|
+
const loaded = await entity.Load(this.conversationDetailId);
|
|
216
|
+
if (!loaded) {
|
|
217
|
+
throw new Error(`ConversationDetail ${this.conversationDetailId} not found in ${this.ratingEntityName}`);
|
|
218
|
+
}
|
|
219
|
+
entity.Set(this.ratingField, rating);
|
|
220
|
+
entity.Set(this.ratingCommentField, comments || null);
|
|
221
|
+
const saveResult = await entity.Save();
|
|
222
|
+
if (!saveResult) {
|
|
223
|
+
throw new Error(`Save failed: ${entity.LatestResult?.Message ?? 'unknown'}`);
|
|
224
|
+
}
|
|
225
|
+
const conversationID = entity.Get('ConversationID');
|
|
226
|
+
return typeof conversationID === 'string' ? conversationID : null;
|
|
146
227
|
}
|
|
147
228
|
catch (error) {
|
|
148
|
-
|
|
149
|
-
console.error('Failed to save rating:', error);
|
|
229
|
+
console.error('[Rating] save failed:', error);
|
|
150
230
|
this.currentUserRating = prevRating;
|
|
151
|
-
this.
|
|
152
|
-
this.thumbsUpCount = prevThumbsUp;
|
|
153
|
-
this.thumbsDownCount = prevThumbsDown;
|
|
154
|
-
this.totalRatings = prevTotal;
|
|
231
|
+
this.currentUserComments = prevComments;
|
|
155
232
|
this.cdr.detectChanges();
|
|
233
|
+
return null;
|
|
156
234
|
}
|
|
157
235
|
finally {
|
|
158
236
|
this.isSaving = false;
|
|
159
237
|
this.cdr.detectChanges();
|
|
160
238
|
}
|
|
161
239
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
const loaded = await entity.Load(prevRatingId);
|
|
168
|
-
if (loaded) {
|
|
169
|
-
entity.Rating = rating;
|
|
170
|
-
await entity.Save();
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
else {
|
|
174
|
-
// Create new rating
|
|
175
|
-
const md = this.ProviderToUse;
|
|
176
|
-
const entity = await md.GetEntityObject('MJ: Conversation Detail Ratings');
|
|
177
|
-
entity.ConversationDetailID = this.conversationDetailId;
|
|
178
|
-
entity.UserID = this.currentUserId;
|
|
179
|
-
entity.Rating = rating;
|
|
180
|
-
await entity.Save();
|
|
181
|
-
this.currentUserRatingId = entity.ID;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
static ɵfac = function ConversationMessageRatingComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ConversationMessageRatingComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
|
|
185
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ConversationMessageRatingComponent, selectors: [["mj-conversation-message-rating"]], inputs: { conversationDetailId: "conversationDetailId", currentUser: "currentUser", ratingsData: "ratingsData" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 7, vars: 9, consts: [[1, "rating-container"], [1, "aggregate-rating", 3, "title"], [1, "user-rating"], ["title", "This was helpful", "type", "button", 1, "rating-button", "thumbs-up-btn", 3, "click", "disabled"], ["title", "This was not helpful", "type", "button", 1, "rating-button", "thumbs-down-btn", 3, "click", "disabled"], [1, "thumbs-up"], [1, "thumbs-down"], [1, "total-count"]], template: function ConversationMessageRatingComponent_Template(rf, ctx) { if (rf & 1) {
|
|
186
|
-
i0.ɵɵelementStart(0, "div", 0);
|
|
187
|
-
i0.ɵɵconditionalCreate(1, ConversationMessageRatingComponent_Conditional_1_Template, 7, 9, "div", 1);
|
|
188
|
-
i0.ɵɵelementStart(2, "div", 2)(3, "button", 3);
|
|
189
|
-
i0.ɵɵlistener("click", function ConversationMessageRatingComponent_Template_button_click_3_listener() { return ctx.RateThumbsUp(); });
|
|
190
|
-
i0.ɵɵtext(4, " \uD83D\uDC4D ");
|
|
191
|
-
i0.ɵɵelementEnd();
|
|
192
|
-
i0.ɵɵelementStart(5, "button", 4);
|
|
193
|
-
i0.ɵɵlistener("click", function ConversationMessageRatingComponent_Template_button_click_5_listener() { return ctx.RateThumbsDown(); });
|
|
194
|
-
i0.ɵɵtext(6, " \uD83D\uDC4E ");
|
|
195
|
-
i0.ɵɵelementEnd()()();
|
|
240
|
+
static ɵfac = function ConversationMessageRatingComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ConversationMessageRatingComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i1.DialogService)); };
|
|
241
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ConversationMessageRatingComponent, selectors: [["mj-conversation-message-rating"]], inputs: { conversationDetailId: "conversationDetailId", currentUser: "currentUser", canEdit: "canEdit", ratingEntityName: "ratingEntityName", ratingField: "ratingField", ratingCommentField: "ratingCommentField", ratingsData: "ratingsData" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 4, vars: 1, consts: [[1, "rating-container"], [1, "user-rating"], ["type", "button", 1, "rating-button", 3, "has-rated", "disabled", "title"], ["title", "Rating left by the conversation owner \u2014 read-only", 1, "rating-readonly"], ["type", "button", 1, "rating-button", 3, "click", "disabled", "title"], [1, "fa-solid", "fa-pen-to-square"], [1, "my-rating"], [1, "fa-regular", "fa-comment-dots"], [1, "fa-solid", "fa-comment-dots"]], template: function ConversationMessageRatingComponent_Template(rf, ctx) { if (rf & 1) {
|
|
242
|
+
i0.ɵɵelementStart(0, "div", 0)(1, "div", 1);
|
|
243
|
+
i0.ɵɵconditionalCreate(2, ConversationMessageRatingComponent_Conditional_2_Template, 3, 5, "button", 2)(3, ConversationMessageRatingComponent_Conditional_3_Template, 4, 1, "span", 3);
|
|
244
|
+
i0.ɵɵelementEnd()();
|
|
196
245
|
} if (rf & 2) {
|
|
197
|
-
i0.ɵɵadvance();
|
|
198
|
-
i0.ɵɵconditional(ctx.totalRatings > 0 ? 1 : -1);
|
|
199
|
-
i0.ɵɵadvance();
|
|
200
|
-
i0.ɵɵclassProp("has-rated", ctx.currentUserRating != null);
|
|
201
|
-
i0.ɵɵadvance();
|
|
202
|
-
i0.ɵɵclassProp("active", ctx.currentUserRating != null && ctx.currentUserRating >= 8);
|
|
203
|
-
i0.ɵɵproperty("disabled", ctx.isSaving);
|
|
204
246
|
i0.ɵɵadvance(2);
|
|
205
|
-
i0.ɵɵ
|
|
206
|
-
|
|
207
|
-
} }, styles: [".rating-container[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 4px 0;\n }\n\n .aggregate-rating[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n color: var(--mj-text-muted);\n }\n\n .thumbs-up[_ngcontent-%COMP%], .thumbs-down[_ngcontent-%COMP%] {\n opacity: 0.5;\n }\n\n .thumbs-up.has-votes[_ngcontent-%COMP%], .thumbs-down.has-votes[_ngcontent-%COMP%] {\n opacity: 1;\n }\n\n .total-count[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-disabled);\n }\n\n .user-rating[_ngcontent-%COMP%] {\n display: flex;\n gap: 4px;\n margin-left: auto;\n }\n\n .rating-button[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-strong);\n border-radius: 6px;\n padding: 6px 10px;\n cursor: pointer;\n font-size: 16px;\n opacity: 0.6;\n transition: all 0.2s;\n min-width: 36px;\n }\n\n .rating-button[_ngcontent-%COMP%]:hover:not(:disabled) {\n opacity: 1;\n border-color: var(--mj-text-muted);\n }\n\n .rating-button[_ngcontent-%COMP%]:disabled {\n cursor: not-allowed;\n opacity: 0.4;\n }\n\n .rating-button.active[_ngcontent-%COMP%] {\n opacity: 1;\n }\n\n .thumbs-up-btn[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n }\n\n .thumbs-up-btn[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: color-mix(in srgb, var(--mj-status-success) 8%, var(--mj-bg-surface));\n }\n\n .thumbs-up-btn.active[_ngcontent-%COMP%] {\n border-color: var(--mj-status-success);\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n }\n\n .thumbs-down-btn[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n }\n\n .thumbs-down-btn[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: color-mix(in srgb, var(--mj-status-error) 8%, var(--mj-bg-surface));\n }\n\n .thumbs-down-btn.active[_ngcontent-%COMP%] {\n border-color: var(--mj-status-error);\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n }"] });
|
|
247
|
+
i0.ɵɵconditional(ctx.canEdit ? 2 : ctx.currentUserRating != null ? 3 : -1);
|
|
248
|
+
} }, styles: [".rating-container[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 4px 0;\n }\n\n .user-rating[_ngcontent-%COMP%] {\n display: flex;\n gap: 4px;\n margin-left: auto;\n }\n\n .rating-button[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-strong);\n border-radius: 6px;\n padding: 6px 12px;\n cursor: pointer;\n font-size: 13px;\n color: var(--mj-text-primary);\n opacity: 0.85;\n transition: all 0.15s ease;\n }\n\n .rating-button[_ngcontent-%COMP%]:hover:not(:disabled) {\n opacity: 1;\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 6%, var(--mj-bg-surface));\n }\n\n .rating-button[_ngcontent-%COMP%]:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n }\n\n .rating-button.has-rated[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n }\n\n .my-rating[_ngcontent-%COMP%] {\n font-weight: 500;\n }\n\n .rating-readonly[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 12px;\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-sunken);\n cursor: default;\n }"] });
|
|
208
249
|
}
|
|
209
250
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ConversationMessageRatingComponent, [{
|
|
210
251
|
type: Component,
|
|
211
252
|
args: [{ standalone: false, selector: 'mj-conversation-message-rating', template: `
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
</
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
type="button">
|
|
242
|
-
👎
|
|
243
|
-
</button>
|
|
244
|
-
</div>
|
|
245
|
-
</div>
|
|
246
|
-
`, styles: ["\n .rating-container {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 4px 0;\n }\n\n .aggregate-rating {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n color: var(--mj-text-muted);\n }\n\n .thumbs-up, .thumbs-down {\n opacity: 0.5;\n }\n\n .thumbs-up.has-votes, .thumbs-down.has-votes {\n opacity: 1;\n }\n\n .total-count {\n font-size: 12px;\n color: var(--mj-text-disabled);\n }\n\n .user-rating {\n display: flex;\n gap: 4px;\n margin-left: auto;\n }\n\n .rating-button {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-strong);\n border-radius: 6px;\n padding: 6px 10px;\n cursor: pointer;\n font-size: 16px;\n opacity: 0.6;\n transition: all 0.2s;\n min-width: 36px;\n }\n\n .rating-button:hover:not(:disabled) {\n opacity: 1;\n border-color: var(--mj-text-muted);\n }\n\n .rating-button:disabled {\n cursor: not-allowed;\n opacity: 0.4;\n }\n\n .rating-button.active {\n opacity: 1;\n }\n\n .thumbs-up-btn {\n color: var(--mj-status-success);\n }\n\n .thumbs-up-btn:hover:not(:disabled) {\n background: color-mix(in srgb, var(--mj-status-success) 8%, var(--mj-bg-surface));\n }\n\n .thumbs-up-btn.active {\n border-color: var(--mj-status-success);\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n }\n\n .thumbs-down-btn {\n color: var(--mj-status-error);\n }\n\n .thumbs-down-btn:hover:not(:disabled) {\n background: color-mix(in srgb, var(--mj-status-error) 8%, var(--mj-bg-surface));\n }\n\n .thumbs-down-btn.active {\n border-color: var(--mj-status-error);\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n }\n "] }]
|
|
247
|
-
}], () => [{ type: i0.ChangeDetectorRef }], { conversationDetailId: [{
|
|
253
|
+
<div class="rating-container">
|
|
254
|
+
<div class="user-rating">
|
|
255
|
+
@if (canEdit) {
|
|
256
|
+
<button
|
|
257
|
+
class="rating-button"
|
|
258
|
+
[class.has-rated]="currentUserRating != null"
|
|
259
|
+
[disabled]="isSaving"
|
|
260
|
+
(click)="OpenRatingDialog()"
|
|
261
|
+
[title]="currentUserRating != null ? 'Edit your rating' : 'Rate this response'"
|
|
262
|
+
type="button">
|
|
263
|
+
@if (currentUserRating != null) {
|
|
264
|
+
<i class="fa-solid fa-pen-to-square"></i>
|
|
265
|
+
<span class="my-rating">My rating: {{ currentUserRating }}/10</span>
|
|
266
|
+
} @else {
|
|
267
|
+
<i class="fa-regular fa-comment-dots"></i>
|
|
268
|
+
<span>Rate response</span>
|
|
269
|
+
}
|
|
270
|
+
</button>
|
|
271
|
+
} @else if (currentUserRating != null) {
|
|
272
|
+
<span class="rating-readonly"
|
|
273
|
+
title="Rating left by the conversation owner — read-only">
|
|
274
|
+
<i class="fa-solid fa-comment-dots"></i>
|
|
275
|
+
<span>Rated {{ currentUserRating }}/10</span>
|
|
276
|
+
</span>
|
|
277
|
+
}
|
|
278
|
+
</div>
|
|
279
|
+
</div>
|
|
280
|
+
`, styles: ["\n .rating-container {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 4px 0;\n }\n\n .user-rating {\n display: flex;\n gap: 4px;\n margin-left: auto;\n }\n\n .rating-button {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-strong);\n border-radius: 6px;\n padding: 6px 12px;\n cursor: pointer;\n font-size: 13px;\n color: var(--mj-text-primary);\n opacity: 0.85;\n transition: all 0.15s ease;\n }\n\n .rating-button:hover:not(:disabled) {\n opacity: 1;\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 6%, var(--mj-bg-surface));\n }\n\n .rating-button:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n }\n\n .rating-button.has-rated {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n }\n\n .my-rating {\n font-weight: 500;\n }\n\n .rating-readonly {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 12px;\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-sunken);\n cursor: default;\n }\n "] }]
|
|
281
|
+
}], () => [{ type: i0.ChangeDetectorRef }, { type: i1.DialogService }], { conversationDetailId: [{
|
|
248
282
|
type: Input
|
|
249
283
|
}], currentUser: [{
|
|
250
284
|
type: Input
|
|
285
|
+
}], canEdit: [{
|
|
286
|
+
type: Input
|
|
287
|
+
}], ratingEntityName: [{
|
|
288
|
+
type: Input
|
|
289
|
+
}], ratingField: [{
|
|
290
|
+
type: Input
|
|
291
|
+
}], ratingCommentField: [{
|
|
292
|
+
type: Input
|
|
251
293
|
}], ratingsData: [{
|
|
252
294
|
type: Input
|
|
253
295
|
}] }); })();
|
|
254
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ConversationMessageRatingComponent, { className: "ConversationMessageRatingComponent", filePath: "src/lib/components/message/conversation-message-rating.component.ts", lineNumber:
|
|
296
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ConversationMessageRatingComponent, { className: "ConversationMessageRatingComponent", filePath: "src/lib/components/message/conversation-message-rating.component.ts", lineNumber: 126 }); })();
|
|
255
297
|
//# sourceMappingURL=conversation-message-rating.component.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation-message-rating.component.js","sourceRoot":"","sources":["../../../../src/lib/components/message/conversation-message-rating.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, OnInit, ChangeDetectorRef } from '@angular/core';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nimport { Metadata, RunView, UserInfo } from '@memberjunction/core';\nimport { MJConversationDetailRatingEntity, RatingJSON } from '@memberjunction/core-entities';\nimport { UUIDsEqual } from '@memberjunction/global';\n\n/**\n * Component for displaying and managing multi-user ratings on conversation messages.\n * Shows aggregate ratings and allows users to provide their own rating.\n * Uses optimistic updates — UI reflects the change immediately while DB saves in background.\n */\n@Component({\n standalone: false,\n selector: 'mj-conversation-message-rating',\n template: `\n <div class=\"rating-container\">\n @if (totalRatings > 0) {\n <div class=\"aggregate-rating\" [title]=\"getRatingsTooltip()\">\n <span class=\"thumbs-up\" [class.has-votes]=\"thumbsUpCount > 0\">\n 👍 {{ thumbsUpCount }}\n </span>\n <span class=\"thumbs-down\" [class.has-votes]=\"thumbsDownCount > 0\">\n 👎 {{ thumbsDownCount }}\n </span>\n <span class=\"total-count\">({{ totalRatings }} {{ totalRatings === 1 ? 'rating' : 'ratings' }})</span>\n </div>\n }\n\n <div class=\"user-rating\" [class.has-rated]=\"currentUserRating != null\">\n <button\n class=\"rating-button thumbs-up-btn\"\n [class.active]=\"currentUserRating != null && currentUserRating >= 8\"\n [disabled]=\"isSaving\"\n (click)=\"RateThumbsUp()\"\n title=\"This was helpful\"\n type=\"button\">\n 👍\n </button>\n <button\n class=\"rating-button thumbs-down-btn\"\n [class.active]=\"currentUserRating != null && currentUserRating <= 3\"\n [disabled]=\"isSaving\"\n (click)=\"RateThumbsDown()\"\n title=\"This was not helpful\"\n type=\"button\">\n 👎\n </button>\n </div>\n </div>\n `,\n styles: [`\n .rating-container {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 4px 0;\n }\n\n .aggregate-rating {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n color: var(--mj-text-muted);\n }\n\n .thumbs-up, .thumbs-down {\n opacity: 0.5;\n }\n\n .thumbs-up.has-votes, .thumbs-down.has-votes {\n opacity: 1;\n }\n\n .total-count {\n font-size: 12px;\n color: var(--mj-text-disabled);\n }\n\n .user-rating {\n display: flex;\n gap: 4px;\n margin-left: auto;\n }\n\n .rating-button {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-strong);\n border-radius: 6px;\n padding: 6px 10px;\n cursor: pointer;\n font-size: 16px;\n opacity: 0.6;\n transition: all 0.2s;\n min-width: 36px;\n }\n\n .rating-button:hover:not(:disabled) {\n opacity: 1;\n border-color: var(--mj-text-muted);\n }\n\n .rating-button:disabled {\n cursor: not-allowed;\n opacity: 0.4;\n }\n\n .rating-button.active {\n opacity: 1;\n }\n\n .thumbs-up-btn {\n color: var(--mj-status-success);\n }\n\n .thumbs-up-btn:hover:not(:disabled) {\n background: color-mix(in srgb, var(--mj-status-success) 8%, var(--mj-bg-surface));\n }\n\n .thumbs-up-btn.active {\n border-color: var(--mj-status-success);\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n }\n\n .thumbs-down-btn {\n color: var(--mj-status-error);\n }\n\n .thumbs-down-btn:hover:not(:disabled) {\n background: color-mix(in srgb, var(--mj-status-error) 8%, var(--mj-bg-surface));\n }\n\n .thumbs-down-btn.active {\n border-color: var(--mj-status-error);\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n }\n `]\n})\nexport class ConversationMessageRatingComponent extends BaseAngularComponent implements OnInit {\n @Input() conversationDetailId!: string;\n @Input() currentUser!: UserInfo;\n @Input() ratingsData?: RatingJSON[];\n\n thumbsUpCount = 0;\n thumbsDownCount = 0;\n totalRatings = 0;\n currentUserRating: number | null = null;\n isSaving = false;\n\n private allRatings: RatingJSON[] = [];\n private currentUserRatingId: string | null = null;\n\n private get currentUserId(): string {\n return this.currentUser?.ID || '';\n }\n\n constructor(private cdr: ChangeDetectorRef) {\n super();}\n\n async ngOnInit() {\n if (this.ratingsData) {\n this.processRatings(this.ratingsData);\n } else {\n await this.loadRatings();\n }\n }\n\n private processRatings(ratings: RatingJSON[] | MJConversationDetailRatingEntity[]): void {\n this.allRatings = ratings as RatingJSON[];\n this.thumbsUpCount = ratings.filter(r => r.Rating != null && r.Rating >= 8).length;\n this.thumbsDownCount = ratings.filter(r => r.Rating != null && r.Rating <= 3).length;\n this.totalRatings = ratings.length;\n\n const mine = ratings.find(r => UUIDsEqual(r.UserID, this.currentUserId));\n this.currentUserRating = mine?.Rating ?? null;\n this.currentUserRatingId = mine ? (mine as RatingJSON).ID ?? null : null;\n }\n\n getRatingsTooltip(): string {\n if (this.allRatings.length === 0) return '';\n\n const upUsers = this.allRatings\n .filter(r => r.Rating != null && r.Rating >= 8)\n .map(r => (r as RatingJSON).UserName || 'Unknown')\n .join(', ');\n\n const downUsers = this.allRatings\n .filter(r => r.Rating != null && r.Rating <= 3)\n .map(r => (r as RatingJSON).UserName || 'Unknown')\n .join(', ');\n\n const parts: string[] = [];\n if (upUsers) parts.push(`👍 ${upUsers}`);\n if (downUsers) parts.push(`👎 ${downUsers}`);\n return parts.join('\\n');\n }\n\n async RateThumbsUp(): Promise<void> {\n await this.saveRating(10);\n }\n\n async RateThumbsDown(): Promise<void> {\n await this.saveRating(1);\n }\n\n private async loadRatings(): Promise<void> {\n try {\n const rv = RunView.FromMetadataProvider(this.ProviderToUse);\n const result = await rv.RunView<MJConversationDetailRatingEntity>({\n EntityName: 'MJ: Conversation Detail Ratings',\n ExtraFilter: `ConversationDetailID='${this.conversationDetailId}'`,\n ResultType: 'entity_object'\n });\n if (result.Success && result.Results) {\n this.processRatings(result.Results);\n this.cdr.detectChanges();\n }\n } catch (error) {\n console.error('Failed to load ratings:', error);\n }\n }\n\n private applyOptimisticUpdate(rating: number): void {\n const wasThumbsUp = this.currentUserRating != null && this.currentUserRating >= 8;\n const wasThumbsDown = this.currentUserRating != null && this.currentUserRating <= 3;\n\n // Adjust counts when switching from an existing rating\n if (wasThumbsUp) this.thumbsUpCount--;\n if (wasThumbsDown) this.thumbsDownCount--;\n if (!wasThumbsUp && !wasThumbsDown) this.totalRatings++;\n\n this.currentUserRating = rating;\n if (rating >= 8) this.thumbsUpCount++;\n else this.thumbsDownCount++;\n }\n\n private async saveRating(rating: number): Promise<void> {\n if (this.isSaving) return;\n\n // Ignore if user clicks the same rating they already have\n if (this.currentUserRating === rating) return;\n\n // Snapshot for rollback\n const prevRating = this.currentUserRating;\n const prevRatingId = this.currentUserRatingId;\n const prevThumbsUp = this.thumbsUpCount;\n const prevThumbsDown = this.thumbsDownCount;\n const prevTotal = this.totalRatings;\n\n // Optimistic update — UI reflects change instantly\n this.isSaving = true;\n this.applyOptimisticUpdate(rating);\n this.cdr.detectChanges();\n\n try {\n await this.persistRating(rating, prevRatingId);\n } catch (error) {\n // Roll back to previous state on failure\n console.error('Failed to save rating:', error);\n this.currentUserRating = prevRating;\n this.currentUserRatingId = prevRatingId;\n this.thumbsUpCount = prevThumbsUp;\n this.thumbsDownCount = prevThumbsDown;\n this.totalRatings = prevTotal;\n this.cdr.detectChanges();\n } finally {\n this.isSaving = false;\n this.cdr.detectChanges();\n }\n }\n\n private async persistRating(rating: number, prevRatingId: string | null): Promise<void> {\n if (prevRatingId) {\n // Update existing rating (switch thumbs up ↔ down)\n const md = this.ProviderToUse;\n const entity = await md.GetEntityObject<MJConversationDetailRatingEntity>('MJ: Conversation Detail Ratings');\n const loaded = await entity.Load(prevRatingId);\n if (loaded) {\n entity.Rating = rating;\n await entity.Save();\n }\n } else {\n // Create new rating\n const md = this.ProviderToUse;\n const entity = await md.GetEntityObject<MJConversationDetailRatingEntity>('MJ: Conversation Detail Ratings');\n entity.ConversationDetailID = this.conversationDetailId;\n entity.UserID = this.currentUserId;\n entity.Rating = rating;\n await entity.Save();\n this.currentUserRatingId = entity.ID;\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"conversation-message-rating.component.js","sourceRoot":"","sources":["../../../../src/lib/components/message/conversation-message-rating.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAA6B,MAAM,eAAe,CAAC;AAC5E,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAA4B,OAAO,EAAY,MAAM,sBAAsB,CAAC;AACnF,OAAO,EAAc,cAAc,EAAE,MAAM,+BAA+B,CAAC;;;;IA0C7D,uBAAyC;IACzC,+BAAwB;IAAA,YAAqC;IAAA,iBAAO;;;IAA5C,eAAqC;IAArC,qEAAqC;;;IAE7D,uBAA0C;IAC1C,4BAAM;IAAA,6BAAa;IAAA,iBAAO;;;;IAZ9B,iCAMgB;IAFd,sMAAS,yBAAkB,KAAC;IAM1B,AAHF,wGAAiC,kFAGxB;IAIX,iBAAS;;;IAZP,6DAA6C;IAG7C,AAFA,0CAAqB,uFAE0D;IAE/E,cAMC;IAND,0DAMC;;;IAGH,+BACgE;IAC9D,uBAAwC;IACxC,4BAAM;IAAA,YAAgC;IACxC,AADwC,iBAAO,EACxC;;;IADC,eAAgC;IAAhC,gEAAgC;;AAlDlD,MAAM,oBAAoB,GAAG,8BAA8B,CAAC;AAC5D,MAAM,8BAA8B,GAAG,sCAAsC,CAAC;AAC9E,MAAM,iBAAiB,GAAG;IACxB,sCAAsC,EAAE,YAAY;IACpD,sCAAsC,CAAE,cAAc;CACvD,CAAC;AAUF;;;;;;;;GAQG;AAgGH,MAAM,OAAO,kCAAmC,SAAQ,oBAAoB;IAqChE;IACA;IArCD,oBAAoB,CAAU;IAC9B,WAAW,CAAY;IAEhC;;;;;OAKG;IACM,OAAO,GAAY,IAAI,CAAC;IAEjC;;;;OAIG;IACM,gBAAgB,GAAW,0BAA0B,CAAC;IAE/D,wDAAwD;IAC/C,WAAW,GAAW,YAAY,CAAC;IAE5C,+DAA+D;IACtD,kBAAkB,GAAW,cAAc,CAAC;IAErD;;;;OAIG;IACM,WAAW,CAAgB;IAEpC,iBAAiB,GAAkB,IAAI,CAAC;IACxC,mBAAmB,GAAW,EAAE,CAAC;IACjC,QAAQ,GAAG,KAAK,CAAC;IAEjB,YACU,GAAsB,EACtB,aAA4B;QAEpC,KAAK,EAAE,CAAC;QAHA,QAAG,GAAH,GAAG,CAAmB;QACtB,kBAAa,GAAb,aAAa,CAAe;IAGtC,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,gBAAgB;QACpB,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC1B,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO;QAE1B,IAAI,mBAAmB,GAAG,KAAK,CAAC;QAChC,IAAI,CAAC;YACH,MAAM,cAAc,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;YACvC,mBAAmB,GAAG,cAAc,CAAC,QAAQ,CAAC,UAAU,CAAC,oBAAoB,CAAC,KAAK,MAAM,CAAC;QAC5F,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,CAAC,IAAI,CAAC,oEAAoE,EAAE,CAAC,CAAC,CAAC;QACxF,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC;YAC7C,KAAK,EAAE,IAAI,CAAC,iBAAiB,IAAI,IAAI,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,oBAAoB;YACjF,OAAO,EAAE,mFAAmF;YAC5F,aAAa,EAAE,IAAI,CAAC,iBAAiB;YACrC,eAAe,EAAE,IAAI,CAAC,mBAAmB;YACzC,MAAM,EAAE,QAAQ;YAChB,cAAc,EAAE,CAAC,mBAAmB;SACrC,CAAC,CAAC;QAEH,IAAI,MAAM,IAAI,IAAI;YAAE,OAAO;QAE3B,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;QAE7E,IAAI,MAAM,CAAC,wBAAwB,EAAE,CAAC;YACpC,IAAI,CAAC;gBACH,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,QAAQ,CAAC,UAAU,CAAC,oBAAoB,EAAE,MAAM,CAAC,CAAC;gBACrF,IAAI,CAAC,KAAK,EAAE,CAAC;oBACX,OAAO,CAAC,KAAK,CACX,iEAAiE,oBAAoB,MAAM;wBAC3F,iFAAiF;wBACjF,6DAA6D,CAC9D,CAAC;gBACJ,CAAC;YACH,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,OAAO,CAAC,KAAK,CAAC,yCAAyC,EAAE,CAAC,CAAC,CAAC;YAC9D,CAAC;QACH,CAAC;QAED,IAAI,cAAc,EAAE,CAAC;YACnB,MAAM,IAAI,CAAC,uBAAuB,CAAC,cAAc,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACK,KAAK,CAAC,uBAAuB,CAAC,cAAsB;QAC1D,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,IAAI,CAAC,aAAa,CAAC;YAC9B,MAAM,EAAE,GAAG,IAAI,OAAO,EAAE,CAAC;YACzB,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC;gBAChC,UAAU,EAAE,0BAA0B;gBACtC,WAAW,EACT,mBAAmB,8BAA8B,QAAQ;oBACzD,qBAAqB,cAAc,wBAAwB;oBAC3D,eAAe,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI;aACnD,CAAC,CAAC;YAEH,MAAM,OAAO,GAAG,IAAI,GAAG,CACrB,CAAC,QAAQ,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CACzE,CAAC;YAEF,KAAK,MAAM,MAAM,IAAI,iBAAiB,EAAE,CAAC;gBACvC,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;oBAAE,SAAS;gBAChD,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,eAAe,CAAC,0BAA0B,CAAC,CAAC;gBAClE,IAAI,CAAC,SAAS,EAAE,CAAC;gBACjB,IAAI,CAAC,GAAG,CAAC,gBAAgB,EAAE,8BAA8B,CAAC,CAAC;gBAC3D,IAAI,CAAC,GAAG,CAAC,kBAAkB,EAAE,cAAc,CAAC,CAAC;gBAC7C,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;gBACzB,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;gBAC3B,IAAI,CAAC,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAAC;gBACpC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;gBAC/B,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;gBAC7B,IAAI,CAAC,EAAE,EAAE,CAAC;oBACR,OAAO,CAAC,IAAI,CAAC,uDAAuD,EAAE,MAAM,EAAG,IAAY,CAAC,YAAY,CAAC,CAAC;gBAC5G,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,CAAC,IAAI,CAAC,0CAA0C,EAAE,CAAC,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,UAAU;QACtB,IAAI,CAAC,IAAI,CAAC,oBAAoB;YAAE,OAAO;QACvC,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,IAAI,CAAC,aAAa,CAAC;YAC9B,MAAM,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAmB,CAAC;YACnF,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;YAC5D,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;gBAC5C,IAAI,CAAC,iBAAiB,GAAG,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;gBAChE,IAAI,CAAC,mBAAmB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,kBAAkB,CAAC,IAAI,EAAE,CAAW,CAAC;gBACjF,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;YAC3B,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,gFAAgF;YAChF,OAAO,CAAC,IAAI,CAAC,6DAA6D,EAAE,KAAK,CAAC,CAAC;QACrF,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,UAAU,CAAC,MAAc,EAAE,QAAgB;QACvD,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC;QAC/B,IAAI,MAAM,GAAG,CAAC,IAAI,MAAM,GAAG,EAAE;YAAE,OAAO,IAAI,CAAC;QAC3C,IAAI,CAAC,IAAI,CAAC,oBAAoB;YAAE,OAAO,IAAI,CAAC;QAE5C,MAAM,UAAU,GAAG,IAAI,CAAC,iBAAiB,CAAC;QAC1C,MAAM,YAAY,GAAG,IAAI,CAAC,mBAAmB,CAAC;QAE9C,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,IAAI,CAAC,iBAAiB,GAAG,MAAM,CAAC;QAChC,IAAI,CAAC,mBAAmB,GAAG,QAAQ,CAAC;QACpC,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;QAEzB,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,IAAI,CAAC,aAAa,CAAC;YAC9B,MAAM,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAmB,CAAC;YACnF,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;YAC5D,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,MAAM,IAAI,KAAK,CAAC,sBAAsB,IAAI,CAAC,oBAAoB,iBAAiB,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAC;YAC3G,CAAC;YACD,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;YACrC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,kBAAkB,EAAE,QAAQ,IAAI,IAAI,CAAC,CAAC;YACtD,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;YACvC,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,MAAM,IAAI,KAAK,CAAC,gBAAiB,MAAc,CAAC,YAAY,EAAE,OAAO,IAAI,SAAS,EAAE,CAAC,CAAC;YACxF,CAAC;YACD,MAAM,cAAc,GAAG,MAAM,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;YACpD,OAAO,OAAO,cAAc,KAAK,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC;QACpE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,uBAAuB,EAAE,KAAK,CAAC,CAAC;YAC9C,IAAI,CAAC,iBAAiB,GAAG,UAAU,CAAC;YACpC,IAAI,CAAC,mBAAmB,GAAG,YAAY,CAAC;YACxC,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;YACzB,OAAO,IAAI,CAAC;QACd,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;YACtB,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;QAC3B,CAAC;IACH,CAAC;4HA9LU,kCAAkC;6DAAlC,kCAAkC;YA1FzC,AADF,8BAA8B,aACH;YAiBrB,AAhBF,uGAAe,+EAgByB;YAQ5C,AADE,iBAAM,EACF;;YAxBF,eAsBC;YAtBD,0EAsBC;;;iFAmEI,kCAAkC;cA/F9C,SAAS;6BACI,KAAK,YACP,gCAAgC,YAChC;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BT;;kBAiEA,KAAK;;kBACL,KAAK;;kBAQL,KAAK;;kBAOL,KAAK;;kBAGL,KAAK;;kBAGL,KAAK;;kBAOL,KAAK;;kFA9BK,kCAAkC","sourcesContent":["import { Component, Input, OnInit, ChangeDetectorRef } from '@angular/core';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nimport { BaseEntity, CompositeKey, RunView, UserInfo } from '@memberjunction/core';\nimport { RatingJSON, UserInfoEngine } from '@memberjunction/core-entities';\nimport { DialogService } from '../../services/dialog.service';\n\nconst FEEDBACK_CONSENT_KEY = 'agent-feedback-share-consent';\nconst CONVERSATIONS_RESOURCE_TYPE_ID = '81D4BC3D-9FEB-EF11-B01A-286B35C04427';\nconst FEEDBACK_ROLE_IDS = [\n 'deafccec-6a37-ef11-86d4-000d3a4e707e', // Developer\n 'dfafccec-6a37-ef11-86d4-000d3a4e707e' // Integration\n];\n\n/** Minimal shape we use against the loaded entity. All MJ entity subclasses\n * implement `Load(ID)` via codegen but the base `BaseEntity<unknown>` type\n * doesn't expose it, so we narrow here to keep the call generic across\n * entity names without resorting to `any`. */\ntype LoadableEntity = BaseEntity<unknown> & {\n Load(KeyValuePairs: CompositeKey | string, EntityRelationshipsToLoad?: string[]): Promise<boolean>;\n};\n\n/**\n * Single-rating-per-message rating UI for an AI conversation response.\n *\n * Storage model: the rating + free-form comment live directly on the\n * ConversationDetail row, in `UserRating` (1-10, nullable) and `UserFeedback`\n * (nvarchar(max), nullable). This matches MJ's own pattern on\n * `__mj.ConversationDetail` and Skip's matching columns on\n * `Skip.ConversationDetail`. The host app picks the entity via @Input.\n */\n@Component({\n standalone: false,\n selector: 'mj-conversation-message-rating',\n template: `\n <div class=\"rating-container\">\n <div class=\"user-rating\">\n @if (canEdit) {\n <button\n class=\"rating-button\"\n [class.has-rated]=\"currentUserRating != null\"\n [disabled]=\"isSaving\"\n (click)=\"OpenRatingDialog()\"\n [title]=\"currentUserRating != null ? 'Edit your rating' : 'Rate this response'\"\n type=\"button\">\n @if (currentUserRating != null) {\n <i class=\"fa-solid fa-pen-to-square\"></i>\n <span class=\"my-rating\">My rating: {{ currentUserRating }}/10</span>\n } @else {\n <i class=\"fa-regular fa-comment-dots\"></i>\n <span>Rate response</span>\n }\n </button>\n } @else if (currentUserRating != null) {\n <span class=\"rating-readonly\"\n title=\"Rating left by the conversation owner — read-only\">\n <i class=\"fa-solid fa-comment-dots\"></i>\n <span>Rated {{ currentUserRating }}/10</span>\n </span>\n }\n </div>\n </div>\n `,\n styles: [`\n .rating-container {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 4px 0;\n }\n\n .user-rating {\n display: flex;\n gap: 4px;\n margin-left: auto;\n }\n\n .rating-button {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-strong);\n border-radius: 6px;\n padding: 6px 12px;\n cursor: pointer;\n font-size: 13px;\n color: var(--mj-text-primary);\n opacity: 0.85;\n transition: all 0.15s ease;\n }\n\n .rating-button:hover:not(:disabled) {\n opacity: 1;\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 6%, var(--mj-bg-surface));\n }\n\n .rating-button:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n }\n\n .rating-button.has-rated {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n }\n\n .my-rating {\n font-weight: 500;\n }\n\n .rating-readonly {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 12px;\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-sunken);\n cursor: default;\n }\n `]\n})\nexport class ConversationMessageRatingComponent extends BaseAngularComponent implements OnInit {\n @Input() conversationDetailId!: string;\n @Input() currentUser!: UserInfo;\n\n /**\n * When false, the rating UI renders as a read-only badge instead of an editable\n * button. Set by the parent (MessageItemComponent) to `false` when the current\n * user is not the conversation owner — the rating storage is a single field on\n * the ConversationDetail row, so only the owner is allowed to mutate it.\n */\n @Input() canEdit: boolean = true;\n\n /**\n * Entity name to load/update for the rating. Defaults to MJ's\n * `MJ: Conversation Details` (which has `UserRating`/`UserFeedback`).\n * Skip-Brain hosts pass `'Conversation Details__Skip'`.\n */\n @Input() ratingEntityName: string = 'MJ: Conversation Details';\n\n /** Column on the entity that stores the 1-10 rating. */\n @Input() ratingField: string = 'UserRating';\n\n /** Column on the entity that stores the free-form feedback. */\n @Input() ratingCommentField: string = 'UserFeedback';\n\n /**\n * Optional: legacy pre-loaded ratings array (no longer used by storage; kept\n * to preserve the input shape used by existing call sites like\n * MessageItemComponent).\n */\n @Input() ratingsData?: RatingJSON[];\n\n currentUserRating: number | null = null;\n currentUserComments: string = '';\n isSaving = false;\n\n constructor(\n private cdr: ChangeDetectorRef,\n private dialogService: DialogService\n ) {\n super();\n }\n\n async ngOnInit() {\n await this.loadRating();\n }\n\n async OpenRatingDialog(): Promise<void> {\n if (this.isSaving) return;\n if (!this.canEdit) return;\n\n let consentAcknowledged = false;\n try {\n await UserInfoEngine.Instance.Config();\n consentAcknowledged = UserInfoEngine.Instance.GetSetting(FEEDBACK_CONSENT_KEY) === 'true';\n } catch (e) {\n console.warn('[Rating] Could not read consent flag, will require acknowledgement', e);\n }\n\n const result = await this.dialogService.rating({\n title: this.currentUserRating != null ? 'Edit your rating' : 'Rate this response',\n message: 'Rate the response on a 1-10 scale and (optionally) describe what was good or bad.',\n initialRating: this.currentUserRating,\n initialComments: this.currentUserComments,\n okText: 'Submit',\n requireConsent: !consentAcknowledged\n });\n\n if (result == null) return;\n\n const conversationID = await this.saveRating(result.rating, result.comments);\n\n if (result.consentNewlyAcknowledged) {\n try {\n const saved = await UserInfoEngine.Instance.SetSetting(FEEDBACK_CONSENT_KEY, 'true');\n if (!saved) {\n console.error(\n `[Rating] Failed to persist consent acknowledgement under key \"${FEEDBACK_CONSENT_KEY}\" — ` +\n `the dialog will re-prompt on next rating. Likely cause: the current user lacks ` +\n `create/update permission on the \"MJ: User Settings\" entity.`\n );\n }\n } catch (e) {\n console.error('[Rating] Could not persist consent flag', e);\n }\n }\n\n if (conversationID) {\n await this.grantConversationAccess(conversationID);\n }\n }\n\n /**\n * Grants the Integrations and Developer roles View access to the parent\n * Conversation via `MJ: Resource Permissions`. Idempotent — existing\n * permissions for the same role are not duplicated. Best-effort; any error\n * is logged but does not roll back the rating itself.\n */\n private async grantConversationAccess(conversationID: string): Promise<void> {\n try {\n const md = this.ProviderToUse;\n const rv = new RunView();\n const existing = await rv.RunView({\n EntityName: 'MJ: Resource Permissions',\n ExtraFilter:\n `ResourceTypeID='${CONVERSATIONS_RESOURCE_TYPE_ID}' AND ` +\n `ResourceRecordID='${conversationID}' AND Type='Role' AND ` +\n `RoleID IN ('${FEEDBACK_ROLE_IDS.join(\"','\")}')`\n });\n\n const granted = new Set<string>(\n (existing.Results || []).map((r: any) => (r.RoleID || '').toLowerCase())\n );\n\n for (const roleID of FEEDBACK_ROLE_IDS) {\n if (granted.has(roleID.toLowerCase())) continue;\n const perm = await md.GetEntityObject('MJ: Resource Permissions');\n perm.NewRecord();\n perm.Set('ResourceTypeID', CONVERSATIONS_RESOURCE_TYPE_ID);\n perm.Set('ResourceRecordID', conversationID);\n perm.Set('Type', 'Role');\n perm.Set('RoleID', roleID);\n perm.Set('PermissionLevel', 'View');\n perm.Set('Status', 'Approved');\n const ok = await perm.Save();\n if (!ok) {\n console.warn('[Rating] Failed to create ResourcePermission for role', roleID, (perm as any).LatestResult);\n }\n }\n } catch (e) {\n console.warn('[Rating] grantConversationAccess failed:', e);\n }\n }\n\n private async loadRating(): Promise<void> {\n if (!this.conversationDetailId) return;\n try {\n const md = this.ProviderToUse;\n const entity = (await md.GetEntityObject(this.ratingEntityName)) as LoadableEntity;\n const loaded = await entity.Load(this.conversationDetailId);\n if (loaded) {\n const rating = entity.Get(this.ratingField);\n this.currentUserRating = rating != null ? Number(rating) : null;\n this.currentUserComments = (entity.Get(this.ratingCommentField) ?? '') as string;\n this.cdr.detectChanges();\n }\n } catch (error) {\n // Silently swallow — message may not be persisted yet, or entity lookup failed.\n console.warn('[ConversationMessageRating] Could not load existing rating:', error);\n }\n }\n\n private async saveRating(rating: number, comments: string): Promise<string | null> {\n if (this.isSaving) return null;\n if (rating < 1 || rating > 10) return null;\n if (!this.conversationDetailId) return null;\n\n const prevRating = this.currentUserRating;\n const prevComments = this.currentUserComments;\n\n this.isSaving = true;\n this.currentUserRating = rating;\n this.currentUserComments = comments;\n this.cdr.detectChanges();\n\n try {\n const md = this.ProviderToUse;\n const entity = (await md.GetEntityObject(this.ratingEntityName)) as LoadableEntity;\n const loaded = await entity.Load(this.conversationDetailId);\n if (!loaded) {\n throw new Error(`ConversationDetail ${this.conversationDetailId} not found in ${this.ratingEntityName}`);\n }\n entity.Set(this.ratingField, rating);\n entity.Set(this.ratingCommentField, comments || null);\n const saveResult = await entity.Save();\n if (!saveResult) {\n throw new Error(`Save failed: ${(entity as any).LatestResult?.Message ?? 'unknown'}`);\n }\n const conversationID = entity.Get('ConversationID');\n return typeof conversationID === 'string' ? conversationID : null;\n } catch (error) {\n console.error('[Rating] save failed:', error);\n this.currentUserRating = prevRating;\n this.currentUserComments = prevComments;\n this.cdr.detectChanges();\n return null;\n } finally {\n this.isSaving = false;\n this.cdr.detectChanges();\n }\n }\n}\n"]}
|
|
@@ -114,7 +114,7 @@ export declare class MessageInputBoxComponent {
|
|
|
114
114
|
mimeType: string;
|
|
115
115
|
sizeBytes: number;
|
|
116
116
|
artifactVersionId?: string;
|
|
117
|
-
}):
|
|
117
|
+
}): PendingAttachment | undefined;
|
|
118
118
|
static ɵfac: i0.ɵɵFactoryDeclaration<MessageInputBoxComponent, never>;
|
|
119
119
|
static ɵcmp: i0.ɵɵComponentDeclaration<MessageInputBoxComponent, "mj-message-input-box", never, { "placeholder": { "alias": "placeholder"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "value": { "alias": "value"; "required": false; }; "showCharacterCount": { "alias": "showCharacterCount"; "required": false; }; "enableMentions": { "alias": "enableMentions"; "required": false; }; "currentUser": { "alias": "currentUser"; "required": false; }; "rows": { "alias": "rows"; "required": false; }; "enableAttachments": { "alias": "enableAttachments"; "required": false; }; "maxAttachments": { "alias": "maxAttachments"; "required": false; }; "maxAttachmentSizeBytes": { "alias": "maxAttachmentSizeBytes"; "required": false; }; "acceptedFileTypes": { "alias": "acceptedFileTypes"; "required": false; }; }, { "textSubmitted": "textSubmitted"; "valueChange": "valueChange"; "attachmentsChanged": "attachmentsChanged"; "attachmentError": "attachmentError"; "attachmentClicked": "attachmentClicked"; "artifactPickerRequested": "artifactPickerRequested"; }, never, never, false, never>;
|
|
120
120
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-input-box.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/message/message-input-box.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAa,MAAM,eAAe,CAAC;AAClF,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,6CAA6C,CAAC;AAChF,OAAO,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;;AAEhG;;;;;;;;;;;;;;GAcG;AACH,qBAMa,wBAAwB;IACP,aAAa,CAAC,EAAE,sBAAsB,CAAC;IAE1D,WAAW,EAAE,MAAM,CAAsD;IACzE,QAAQ,EAAE,OAAO,CAAS;IAC1B,KAAK,EAAE,MAAM,CAAM;IACnB,kBAAkB,EAAE,OAAO,CAAS;IACpC,cAAc,EAAE,OAAO,CAAQ;IAC/B,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,IAAI,EAAE,MAAM,CAAK;IAGjB,iBAAiB,EAAE,OAAO,CAAQ;IAClC,cAAc,EAAE,MAAM,CAAM;IAC5B,sBAAsB,EAAE,MAAM,CAAoB;IAClD,iBAAiB,EAAE,MAAM,CAAa;IAErC,aAAa,uBAA8B;IAC3C,WAAW,uBAA8B;IACzC,kBAAkB,oCAA2C;IAC7D,eAAe,uBAA8B;IAC7C,iBAAiB,kCAAyC;IAC1D,uBAAuB,qBAA4B;IAE7D,IAAI,OAAO,IAAI,OAAO,CAIrB;IAED;;OAEG;IACH,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAKrC;;OAEG;IACH,oBAAoB,CAAC,WAAW,EAAE,iBAAiB,EAAE,GAAG,IAAI;IAI5D;;OAEG;IACH,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAItC;;OAEG;IACH,mBAAmB,CAAC,UAAU,EAAE,iBAAiB,GAAG,IAAI;IAIxD;;;OAGG;IACH,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAInC;;OAEG;IACH,iBAAiB,CAAC,UAAU,EAAE,iBAAiB,GAAG,IAAI;IAKtD;;;OAGG;IACH,WAAW,IAAI,IAAI;IAgBnB;;;OAGG;IACH,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IA6BzC;;OAEG;IACH,KAAK,IAAI,IAAI;IAOb;;OAEG;IACH,mBAAmB,IAAI,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAIhH;;OAEG;IACH,qBAAqB,IAAI,iBAAiB,EAAE;IAI5C;;OAEG;IACH,cAAc,IAAI,IAAI;IAItB;;;;;;;;OAQG;IACH,kBAAkB,IAAI,IAAI;IAI1B;;OAEG;IACH,qBAAqB,CAAC,QAAQ,EAAE;QAC9B,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QACnD,SAAS,EAAE,MAAM,CAAC;QAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;KAC/C,GAAG,
|
|
1
|
+
{"version":3,"file":"message-input-box.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/message/message-input-box.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAa,MAAM,eAAe,CAAC;AAClF,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,6CAA6C,CAAC;AAChF,OAAO,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;;AAEhG;;;;;;;;;;;;;;GAcG;AACH,qBAMa,wBAAwB;IACP,aAAa,CAAC,EAAE,sBAAsB,CAAC;IAE1D,WAAW,EAAE,MAAM,CAAsD;IACzE,QAAQ,EAAE,OAAO,CAAS;IAC1B,KAAK,EAAE,MAAM,CAAM;IACnB,kBAAkB,EAAE,OAAO,CAAS;IACpC,cAAc,EAAE,OAAO,CAAQ;IAC/B,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,IAAI,EAAE,MAAM,CAAK;IAGjB,iBAAiB,EAAE,OAAO,CAAQ;IAClC,cAAc,EAAE,MAAM,CAAM;IAC5B,sBAAsB,EAAE,MAAM,CAAoB;IAClD,iBAAiB,EAAE,MAAM,CAAa;IAErC,aAAa,uBAA8B;IAC3C,WAAW,uBAA8B;IACzC,kBAAkB,oCAA2C;IAC7D,eAAe,uBAA8B;IAC7C,iBAAiB,kCAAyC;IAC1D,uBAAuB,qBAA4B;IAE7D,IAAI,OAAO,IAAI,OAAO,CAIrB;IAED;;OAEG;IACH,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAKrC;;OAEG;IACH,oBAAoB,CAAC,WAAW,EAAE,iBAAiB,EAAE,GAAG,IAAI;IAI5D;;OAEG;IACH,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAItC;;OAEG;IACH,mBAAmB,CAAC,UAAU,EAAE,iBAAiB,GAAG,IAAI;IAIxD;;;OAGG;IACH,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAInC;;OAEG;IACH,iBAAiB,CAAC,UAAU,EAAE,iBAAiB,GAAG,IAAI;IAKtD;;;OAGG;IACH,WAAW,IAAI,IAAI;IAgBnB;;;OAGG;IACH,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IA6BzC;;OAEG;IACH,KAAK,IAAI,IAAI;IAOb;;OAEG;IACH,mBAAmB,IAAI,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAIhH;;OAEG;IACH,qBAAqB,IAAI,iBAAiB,EAAE;IAI5C;;OAEG;IACH,cAAc,IAAI,IAAI;IAItB;;;;;;;;OAQG;IACH,kBAAkB,IAAI,IAAI;IAI1B;;OAEG;IACH,qBAAqB,CAAC,QAAQ,EAAE;QAC9B,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QACnD,SAAS,EAAE,MAAM,CAAC;QAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;KAC/C,GAAG,iBAAiB,GAAG,SAAS;yCAlLtB,wBAAwB;2CAAxB,wBAAwB;CAqLpC"}
|
|
@@ -187,7 +187,7 @@ export class MessageInputBoxComponent {
|
|
|
187
187
|
* Add an artifact as a pending attachment (called by parent after artifact selection)
|
|
188
188
|
*/
|
|
189
189
|
AddArtifactAttachment(artifact) {
|
|
190
|
-
this.mentionEditor?.AddArtifactAttachment(artifact);
|
|
190
|
+
return this.mentionEditor?.AddArtifactAttachment(artifact);
|
|
191
191
|
}
|
|
192
192
|
static ɵfac = function MessageInputBoxComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MessageInputBoxComponent)(); };
|
|
193
193
|
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MessageInputBoxComponent, selectors: [["mj-message-input-box"]], viewQuery: function MessageInputBoxComponent_Query(rf, ctx) { if (rf & 1) {
|