@memberjunction/core-entities 5.41.0 → 5.42.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/custom/PermissionProviders/AccessControlRuleProvider.d.ts +8 -0
- package/dist/custom/PermissionProviders/AccessControlRuleProvider.d.ts.map +1 -1
- package/dist/custom/PermissionProviders/AccessControlRuleProvider.js +14 -4
- package/dist/custom/PermissionProviders/AccessControlRuleProvider.js.map +1 -1
- package/dist/engines/conversations.d.ts +71 -1
- package/dist/engines/conversations.d.ts.map +1 -1
- package/dist/engines/conversations.js +219 -0
- package/dist/engines/conversations.js.map +1 -1
- package/dist/generated/entity_subclasses.d.ts +1894 -5
- package/dist/generated/entity_subclasses.d.ts.map +1 -1
- package/dist/generated/entity_subclasses.js +3073 -232
- package/dist/generated/entity_subclasses.js.map +1 -1
- package/package.json +5 -5
|
@@ -35,6 +35,14 @@ export declare class AccessControlRuleProvider extends PermissionProviderBase {
|
|
|
35
35
|
* expired ACR can't be acted on, so surfacing it in "Shared by me" would be noise.
|
|
36
36
|
*/
|
|
37
37
|
GetPermissionsGrantedByUser(grantor: UserInfo): Promise<NormalizedPermission[]>;
|
|
38
|
+
/**
|
|
39
|
+
* Dialect-neutral "not yet expired" predicate. Uses a JS-computed ISO-8601
|
|
40
|
+
* timestamp literal rather than a SQL function — SQL Server's `GETUTCDATE()`
|
|
41
|
+
* does not exist on PostgreSQL and would crash the underlying RunView query
|
|
42
|
+
* there. An ISO-8601 literal compares correctly against `datetimeoffset`
|
|
43
|
+
* (SQL Server) and `timestamptz` (PostgreSQL) alike.
|
|
44
|
+
*/
|
|
45
|
+
private unexpiredClause;
|
|
38
46
|
private resolveEntityId;
|
|
39
47
|
private fetchActiveRules;
|
|
40
48
|
private resolveGranteeName;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AccessControlRuleProvider.d.ts","sourceRoot":"","sources":["../../../src/custom/PermissionProviders/AccessControlRuleProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,WAAW,EACX,iBAAiB,EAEjB,oBAAoB,EACpB,gBAAgB,EAChB,qBAAqB,EACrB,sBAAsB,EACtB,QAAQ,EACX,MAAM,sBAAsB,CAAC;AAyB9B;;;;;;;;;;;GAWG;AACH,qBACa,yBAA0B,SAAQ,sBAAsB;IACjE,QAAQ,CAAC,UAAU,0BAA0B;IAC7C,QAAQ,CAAC,WAAW,iHAC8F;IAClH,QAAQ,CAAC,qBAAqB,EAAE,WAAW,EAAE,CAA0C;IACvF,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,EAAE,CAAmD;IAChG,QAAQ,CAAC,YAAY,SAAS;IAC9B,QAAQ,CAAC,kBAAkB,QAAQ;IAE1B,gBAAgB,CAAC,QAAQ,CAAC,EAAE,iBAAiB,GAAG,MAAM,EAAE;IAK3D,eAAe,CACjB,IAAI,EAAE,QAAQ,EACd,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,GAAG,IAAI,EACzB,MAAM,EAAE,gBAAgB,EACxB,QAAQ,CAAC,EAAE,iBAAiB,GAC7B,OAAO,CAAC,qBAAqB,CAAC;IA6B3B,uBAAuB,CAAC,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAchJ,gBAAgB,CAAC,IAAI,EAAE,QAAQ,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAqDtH,sBAAsB,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAsBrI;;;;;OAKG;IACY,4BAA4B,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAyB/F;;;OAGG;IACY,2BAA2B,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;IA0B9F,OAAO,CAAC,eAAe;YAMT,gBAAgB;IAS9B,OAAO,CAAC,kBAAkB;IAc1B,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,kBAAkB;IAc1B,OAAO,CAAC,UAAU;CASrB"}
|
|
1
|
+
{"version":3,"file":"AccessControlRuleProvider.d.ts","sourceRoot":"","sources":["../../../src/custom/PermissionProviders/AccessControlRuleProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,WAAW,EACX,iBAAiB,EAEjB,oBAAoB,EACpB,gBAAgB,EAChB,qBAAqB,EACrB,sBAAsB,EACtB,QAAQ,EACX,MAAM,sBAAsB,CAAC;AAyB9B;;;;;;;;;;;GAWG;AACH,qBACa,yBAA0B,SAAQ,sBAAsB;IACjE,QAAQ,CAAC,UAAU,0BAA0B;IAC7C,QAAQ,CAAC,WAAW,iHAC8F;IAClH,QAAQ,CAAC,qBAAqB,EAAE,WAAW,EAAE,CAA0C;IACvF,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,EAAE,CAAmD;IAChG,QAAQ,CAAC,YAAY,SAAS;IAC9B,QAAQ,CAAC,kBAAkB,QAAQ;IAE1B,gBAAgB,CAAC,QAAQ,CAAC,EAAE,iBAAiB,GAAG,MAAM,EAAE;IAK3D,eAAe,CACjB,IAAI,EAAE,QAAQ,EACd,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,GAAG,IAAI,EACzB,MAAM,EAAE,gBAAgB,EACxB,QAAQ,CAAC,EAAE,iBAAiB,GAC7B,OAAO,CAAC,qBAAqB,CAAC;IA6B3B,uBAAuB,CAAC,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAchJ,gBAAgB,CAAC,IAAI,EAAE,QAAQ,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAqDtH,sBAAsB,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAsBrI;;;;;OAKG;IACY,4BAA4B,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAyB/F;;;OAGG;IACY,2BAA2B,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;IA0B9F;;;;;;OAMG;IACH,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,eAAe;YAMT,gBAAgB;IAS9B,OAAO,CAAC,kBAAkB;IAc1B,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,kBAAkB;IAc1B,OAAO,CAAC,UAAU;CASrB"}
|
|
@@ -87,7 +87,7 @@ let AccessControlRuleProvider = class AccessControlRuleProvider extends Permissi
|
|
|
87
87
|
granteeClauses.push(`(GranteeType='Role' AND GranteeID IN (${userRoleIds.join(',')}))`);
|
|
88
88
|
}
|
|
89
89
|
const granteeFilter = granteeClauses.join(' OR ');
|
|
90
|
-
let filter = `(${granteeFilter}) AND (
|
|
90
|
+
let filter = `(${granteeFilter}) AND ${this.unexpiredClause()}`;
|
|
91
91
|
if (resourceType) {
|
|
92
92
|
const entityId = this.resolveEntityId(resourceType, provider);
|
|
93
93
|
if (!entityId)
|
|
@@ -152,7 +152,7 @@ let AccessControlRuleProvider = class AccessControlRuleProvider extends Permissi
|
|
|
152
152
|
async GetPermissionsSharedWithUser(grantee) {
|
|
153
153
|
const rows = await this.fetchRows('MJ: Access Control Rules', `GranteeType='User' AND GranteeID='${grantee.ID}' ` +
|
|
154
154
|
`AND GrantedByUserID <> '${grantee.ID}' ` +
|
|
155
|
-
`AND (
|
|
155
|
+
`AND ${this.unexpiredClause()}`, ACR_GRANT_FIELDS, 'GetPermissionsSharedWithUser');
|
|
156
156
|
const results = [];
|
|
157
157
|
for (const row of rows) {
|
|
158
158
|
const actions = this.rowActions(row);
|
|
@@ -173,7 +173,7 @@ let AccessControlRuleProvider = class AccessControlRuleProvider extends Permissi
|
|
|
173
173
|
* expired ACR can't be acted on, so surfacing it in "Shared by me" would be noise.
|
|
174
174
|
*/
|
|
175
175
|
async GetPermissionsGrantedByUser(grantor) {
|
|
176
|
-
const rows = await this.fetchRows('MJ: Access Control Rules', `GrantedByUserID='${grantor.ID}' AND (
|
|
176
|
+
const rows = await this.fetchRows('MJ: Access Control Rules', `GrantedByUserID='${grantor.ID}' AND ${this.unexpiredClause()}`, ACR_GRANT_FIELDS, 'GetPermissionsGrantedByUser');
|
|
177
177
|
const results = [];
|
|
178
178
|
for (const row of rows) {
|
|
179
179
|
const actions = this.rowActions(row);
|
|
@@ -192,13 +192,23 @@ let AccessControlRuleProvider = class AccessControlRuleProvider extends Permissi
|
|
|
192
192
|
}
|
|
193
193
|
return results;
|
|
194
194
|
}
|
|
195
|
+
/**
|
|
196
|
+
* Dialect-neutral "not yet expired" predicate. Uses a JS-computed ISO-8601
|
|
197
|
+
* timestamp literal rather than a SQL function — SQL Server's `GETUTCDATE()`
|
|
198
|
+
* does not exist on PostgreSQL and would crash the underlying RunView query
|
|
199
|
+
* there. An ISO-8601 literal compares correctly against `datetimeoffset`
|
|
200
|
+
* (SQL Server) and `timestamptz` (PostgreSQL) alike.
|
|
201
|
+
*/
|
|
202
|
+
unexpiredClause() {
|
|
203
|
+
return `(ExpiresAt IS NULL OR ExpiresAt > '${new Date().toISOString()}')`;
|
|
204
|
+
}
|
|
195
205
|
resolveEntityId(entityName, provider) {
|
|
196
206
|
const md = provider ?? new Metadata();
|
|
197
207
|
const entity = md.EntityByName(entityName);
|
|
198
208
|
return entity?.ID ?? null;
|
|
199
209
|
}
|
|
200
210
|
async fetchActiveRules(entityId, recordId) {
|
|
201
|
-
return this.fetchRows('MJ: Access Control Rules', `EntityID='${entityId}' AND RecordID='${recordId}' AND (
|
|
211
|
+
return this.fetchRows('MJ: Access Control Rules', `EntityID='${entityId}' AND RecordID='${recordId}' AND ${this.unexpiredClause()}`, ACR_GRANT_FIELDS.filter((f) => f !== 'GrantedByUserID' && f !== 'Entity'), 'fetchActiveRules');
|
|
202
212
|
}
|
|
203
213
|
resolveGranteeName(row, provider) {
|
|
204
214
|
switch (row.GranteeType) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AccessControlRuleProvider.js","sourceRoot":"","sources":["../../../src/custom/PermissionProviders/AccessControlRuleProvider.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAGH,QAAQ,EAIR,sBAAsB,GAEzB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAkBnE,oGAAoG;AACpG,MAAM,gBAAgB,GAAa;IAC/B,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,aAAa,EAAE,WAAW,EAAE,iBAAiB;IACrF,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW;CAC5E,CAAC;AAEF;;;;;;;;;;;GAWG;AAEI,IAAM,yBAAyB,GAA/B,MAAM,yBAA0B,SAAQ,sBAAsB;IAA9D;;QACM,eAAU,GAAG,sBAAsB,CAAC;QACpC,gBAAW,GAChB,6GAA6G,CAAC;QACzG,0BAAqB,GAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;QAC9E,qBAAgB,GAAuB,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;QACvF,iBAAY,GAAG,KAAK,CAAC;QACrB,uBAAkB,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"AccessControlRuleProvider.js","sourceRoot":"","sources":["../../../src/custom/PermissionProviders/AccessControlRuleProvider.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BaseEngine, BaseEntityEvent, IMetadataProvider, UserInfo } from "@memberjunction/core";
|
|
2
2
|
import { Observable } from "rxjs";
|
|
3
|
-
import { MJConversationEntity, MJConversationDetailEntity, MJConversationDetailEntityType, MJAIAgentRunEntity, MJAIAgentRunEntityType, MJConversationDetailRatingEntityType, MJConversationDetailArtifactEntityType } from "../generated/entity_subclasses.js";
|
|
3
|
+
import { MJConversationEntity, MJConversationDetailEntity, MJConversationDetailEntityType, MJAIAgentRunEntity, MJAIAgentRunEntityType, MJConversationDetailRatingEntityType, MJConversationDetailArtifactEntityType, MJProjectEntity } from "../generated/entity_subclasses.js";
|
|
4
4
|
/**
|
|
5
5
|
* Display info about the user who shared a conversation with the current user,
|
|
6
6
|
* plus the `PermissionLevel` the grantee was granted. Exposed via
|
|
@@ -180,10 +180,23 @@ export declare class ConversationEngine extends BaseEngine<ConversationEngine> {
|
|
|
180
180
|
* Current snapshot of conversations (non-reactive).
|
|
181
181
|
*/
|
|
182
182
|
get Conversations(): MJConversationEntity[];
|
|
183
|
+
private _projects$;
|
|
184
|
+
/**
|
|
185
|
+
* Observable stream of the projects (conversation folders) for the current
|
|
186
|
+
* environment. Emits whenever projects are loaded or a project is created,
|
|
187
|
+
* renamed, or deleted (kept in sync via the entity event handler).
|
|
188
|
+
*/
|
|
189
|
+
get Projects$(): Observable<MJProjectEntity[]>;
|
|
190
|
+
/**
|
|
191
|
+
* Current snapshot of projects/folders (non-reactive).
|
|
192
|
+
*/
|
|
193
|
+
get Projects(): MJProjectEntity[];
|
|
183
194
|
/** Detail cache keyed by normalized conversation ID */
|
|
184
195
|
private _detailCache;
|
|
185
196
|
/** Track the environment ID used for the last load */
|
|
186
197
|
private _lastEnvironmentId;
|
|
198
|
+
/** Track the environment ID used for the last projects (folders) load */
|
|
199
|
+
private _lastProjectsEnvironmentId;
|
|
187
200
|
/**
|
|
188
201
|
* For conversations the current user *received* via sharing, this map goes
|
|
189
202
|
* from `conversationId` to the grantor's display info. Populated by
|
|
@@ -230,6 +243,56 @@ export declare class ConversationEngine extends BaseEngine<ConversationEngine> {
|
|
|
230
243
|
* are skipped — the UI degrades to no badge for those.
|
|
231
244
|
*/
|
|
232
245
|
private rebuildSharedByMap;
|
|
246
|
+
/**
|
|
247
|
+
* Loads the projects (conversation folders) for an environment and emits via Projects$.
|
|
248
|
+
* Projects are environment-scoped (not user-scoped) and small, so the full active set
|
|
249
|
+
* is cached. Skips reloading when already loaded for the same environment unless forced.
|
|
250
|
+
*
|
|
251
|
+
* @param environmentId - The environment to filter projects by
|
|
252
|
+
* @param contextUser - The current user context
|
|
253
|
+
* @param forceRefresh - If true, reloads even if already cached for this environment
|
|
254
|
+
*/
|
|
255
|
+
LoadProjects(environmentId: string, contextUser: UserInfo, forceRefresh?: boolean): Promise<void>;
|
|
256
|
+
/**
|
|
257
|
+
* Assigns a conversation to a folder (project), or removes it from its folder when
|
|
258
|
+
* projectId is null. Thin wrapper over {@link SaveConversation} that keeps the
|
|
259
|
+
* intent explicit at call sites.
|
|
260
|
+
*
|
|
261
|
+
* @param conversationId - The conversation to move
|
|
262
|
+
* @param projectId - The target project ID, or null to ungroup
|
|
263
|
+
* @param contextUser - The current user context
|
|
264
|
+
* @returns true if saved successfully
|
|
265
|
+
*/
|
|
266
|
+
MoveConversationToProject(conversationId: string, projectId: string | null, contextUser: UserInfo): Promise<boolean>;
|
|
267
|
+
/**
|
|
268
|
+
* Reparents a folder (project) under another folder, or to the top level when
|
|
269
|
+
* parentId is null. Callers are responsible for preventing cycles (don't pass a
|
|
270
|
+
* descendant of the folder as its new parent). Updates the cached entity in place
|
|
271
|
+
* and re-emits Projects$.
|
|
272
|
+
*
|
|
273
|
+
* @param projectId - The folder to move
|
|
274
|
+
* @param parentId - The new parent folder ID, or null for top level
|
|
275
|
+
* @param contextUser - The current user context
|
|
276
|
+
* @returns true if saved successfully
|
|
277
|
+
*/
|
|
278
|
+
MoveProjectToParent(projectId: string, parentId: string | null, contextUser: UserInfo): Promise<boolean>;
|
|
279
|
+
/**
|
|
280
|
+
* Deletes a folder (project) in an FK-safe way. The Conversation→Project and
|
|
281
|
+
* Project→Project (ParentID) foreign keys are RESTRICT, so the row can't be
|
|
282
|
+
* deleted while anything references it. Before deleting, this:
|
|
283
|
+
* 1. Unassigns every conversation directly in the folder (ProjectID → null).
|
|
284
|
+
* 2. Reparents direct child folders to this folder's parent (one level up).
|
|
285
|
+
* 3. Deletes the now-unreferenced folder.
|
|
286
|
+
* Conversations and subfolders are preserved — only the folder itself is removed.
|
|
287
|
+
*
|
|
288
|
+
* Note: this does NOT reassign Tasks that reference the project; if a Task still
|
|
289
|
+
* references it, the final delete will fail and this throws with the DB message.
|
|
290
|
+
*
|
|
291
|
+
* @param id - The project (folder) ID to delete
|
|
292
|
+
* @param contextUser - The current user context
|
|
293
|
+
* @returns true if deleted successfully
|
|
294
|
+
*/
|
|
295
|
+
DeleteProject(id: string, contextUser: UserInfo): Promise<boolean>;
|
|
233
296
|
/**
|
|
234
297
|
* Creates a new conversation, saves it to the database, and adds it to the cached list.
|
|
235
298
|
*
|
|
@@ -475,6 +538,13 @@ export declare class ConversationEngine extends BaseEngine<ConversationEngine> {
|
|
|
475
538
|
* Handles save/delete events on ConversationDetail entities from local or remote code.
|
|
476
539
|
*/
|
|
477
540
|
private handleConversationDetailEntityEvent;
|
|
541
|
+
/**
|
|
542
|
+
* Handles save/delete events on Project entities from local or remote code.
|
|
543
|
+
* Keeps the folder list in sync when a folder is created, renamed, archived, or
|
|
544
|
+
* deleted via the project form modal. Only tracks projects in the currently-loaded
|
|
545
|
+
* environment; archived projects are dropped from the active list.
|
|
546
|
+
*/
|
|
547
|
+
private handleProjectEntityEvent;
|
|
478
548
|
/**
|
|
479
549
|
* Handles save/delete events on AI Agent Run entities from local or remote code.
|
|
480
550
|
* Updates the AgentRunsByDetailId map so timers and status reflect reality.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversations.d.ts","sourceRoot":"","sources":["../../src/engines/conversations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAA4B,eAAe,EAAE,iBAAiB,EAA0D,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAElL,OAAO,EAAmB,UAAU,EAAE,MAAM,MAAM,CAAC;AACnD,OAAO,EACH,oBAAoB,EACpB,0BAA0B,EAC1B,8BAA8B,EAC9B,kBAAkB,EAClB,sBAAsB,EACtB,oCAAoC,EACpC,sCAAsC,
|
|
1
|
+
{"version":3,"file":"conversations.d.ts","sourceRoot":"","sources":["../../src/engines/conversations.ts"],"names":[],"mappings":"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"}
|
|
@@ -62,6 +62,7 @@ export class ConversationEngine extends BaseEngine {
|
|
|
62
62
|
// REACTIVE STATE
|
|
63
63
|
// ========================================================================
|
|
64
64
|
this._conversations$ = new BehaviorSubject([]);
|
|
65
|
+
this._projects$ = new BehaviorSubject([]);
|
|
65
66
|
// ========================================================================
|
|
66
67
|
// INTERNAL STATE
|
|
67
68
|
// ========================================================================
|
|
@@ -69,6 +70,8 @@ export class ConversationEngine extends BaseEngine {
|
|
|
69
70
|
this._detailCache = new Map();
|
|
70
71
|
/** Track the environment ID used for the last load */
|
|
71
72
|
this._lastEnvironmentId = null;
|
|
73
|
+
/** Track the environment ID used for the last projects (folders) load */
|
|
74
|
+
this._lastProjectsEnvironmentId = null;
|
|
72
75
|
/**
|
|
73
76
|
* For conversations the current user *received* via sharing, this map goes
|
|
74
77
|
* from `conversationId` to the grantor's display info. Populated by
|
|
@@ -105,6 +108,20 @@ export class ConversationEngine extends BaseEngine {
|
|
|
105
108
|
get Conversations() {
|
|
106
109
|
return this._conversations$.value;
|
|
107
110
|
}
|
|
111
|
+
/**
|
|
112
|
+
* Observable stream of the projects (conversation folders) for the current
|
|
113
|
+
* environment. Emits whenever projects are loaded or a project is created,
|
|
114
|
+
* renamed, or deleted (kept in sync via the entity event handler).
|
|
115
|
+
*/
|
|
116
|
+
get Projects$() {
|
|
117
|
+
return this._projects$.asObservable();
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Current snapshot of projects/folders (non-reactive).
|
|
121
|
+
*/
|
|
122
|
+
get Projects() {
|
|
123
|
+
return this._projects$.value;
|
|
124
|
+
}
|
|
108
125
|
/**
|
|
109
126
|
* Look up grantor info for a conversation the current user was shared into.
|
|
110
127
|
* Returns `null` for conversations the user owns (not shared with them).
|
|
@@ -200,6 +217,11 @@ export class ConversationEngine extends BaseEngine {
|
|
|
200
217
|
.map((c) => NormalizeUUID(c.ID)));
|
|
201
218
|
const trulySharedPermissions = sharedPermissions.filter((p) => !ownedConversationIds.has(NormalizeUUID(p.ResourceRecordID)));
|
|
202
219
|
await this.rebuildSharedByMap(rv, trulySharedPermissions, contextUser);
|
|
220
|
+
// Load the folder (project) list so the sidebar can group conversations
|
|
221
|
+
// under their folder. Done after the conversation query (so it isn't
|
|
222
|
+
// delayed) and after the early-return guard above; LoadProjects has its
|
|
223
|
+
// own per-environment guard to avoid redundant reloads.
|
|
224
|
+
await this.LoadProjects(environmentId, contextUser, forceRefresh);
|
|
203
225
|
}
|
|
204
226
|
/**
|
|
205
227
|
* Populates {@link _sharedByByConversationId}. Resolves grantor emails via
|
|
@@ -240,6 +262,159 @@ export class ConversationEngine extends BaseEngine {
|
|
|
240
262
|
});
|
|
241
263
|
}
|
|
242
264
|
}
|
|
265
|
+
/**
|
|
266
|
+
* Loads the projects (conversation folders) for an environment and emits via Projects$.
|
|
267
|
+
* Projects are environment-scoped (not user-scoped) and small, so the full active set
|
|
268
|
+
* is cached. Skips reloading when already loaded for the same environment unless forced.
|
|
269
|
+
*
|
|
270
|
+
* @param environmentId - The environment to filter projects by
|
|
271
|
+
* @param contextUser - The current user context
|
|
272
|
+
* @param forceRefresh - If true, reloads even if already cached for this environment
|
|
273
|
+
*/
|
|
274
|
+
async LoadProjects(environmentId, contextUser, forceRefresh = false) {
|
|
275
|
+
if (!forceRefresh && this._lastProjectsEnvironmentId === environmentId) {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
const rv = new RunView();
|
|
279
|
+
const result = await rv.RunView({
|
|
280
|
+
EntityName: 'MJ: Projects',
|
|
281
|
+
ExtraFilter: `EnvironmentID='${environmentId}' AND (IsArchived IS NULL OR IsArchived=0)`,
|
|
282
|
+
OrderBy: 'Name ASC',
|
|
283
|
+
MaxRows: 1000,
|
|
284
|
+
ResultType: 'entity_object'
|
|
285
|
+
}, contextUser);
|
|
286
|
+
if (result.Success) {
|
|
287
|
+
this._lastProjectsEnvironmentId = environmentId;
|
|
288
|
+
this._projects$.next(result.Results || []);
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
console.error('[ConversationEngine] Failed to load projects:', result.ErrorMessage);
|
|
292
|
+
this._projects$.next([]);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Assigns a conversation to a folder (project), or removes it from its folder when
|
|
297
|
+
* projectId is null. Thin wrapper over {@link SaveConversation} that keeps the
|
|
298
|
+
* intent explicit at call sites.
|
|
299
|
+
*
|
|
300
|
+
* @param conversationId - The conversation to move
|
|
301
|
+
* @param projectId - The target project ID, or null to ungroup
|
|
302
|
+
* @param contextUser - The current user context
|
|
303
|
+
* @returns true if saved successfully
|
|
304
|
+
*/
|
|
305
|
+
async MoveConversationToProject(conversationId, projectId, contextUser) {
|
|
306
|
+
return this.SaveConversation(conversationId, { ProjectID: projectId }, contextUser);
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Reparents a folder (project) under another folder, or to the top level when
|
|
310
|
+
* parentId is null. Callers are responsible for preventing cycles (don't pass a
|
|
311
|
+
* descendant of the folder as its new parent). Updates the cached entity in place
|
|
312
|
+
* and re-emits Projects$.
|
|
313
|
+
*
|
|
314
|
+
* @param projectId - The folder to move
|
|
315
|
+
* @param parentId - The new parent folder ID, or null for top level
|
|
316
|
+
* @param contextUser - The current user context
|
|
317
|
+
* @returns true if saved successfully
|
|
318
|
+
*/
|
|
319
|
+
async MoveProjectToParent(projectId, parentId, contextUser) {
|
|
320
|
+
let project = this._projects$.value.find(p => UUIDsEqual(p.ID, projectId));
|
|
321
|
+
if (!project) {
|
|
322
|
+
const md = this.ProviderToUse;
|
|
323
|
+
project = await md.GetEntityObject('MJ: Projects', contextUser);
|
|
324
|
+
const loaded = await project.Load(projectId);
|
|
325
|
+
if (!loaded) {
|
|
326
|
+
throw new Error('Folder not found');
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
project.ParentID = parentId;
|
|
330
|
+
this._selfMutating = true;
|
|
331
|
+
try {
|
|
332
|
+
const saved = await project.Save();
|
|
333
|
+
if (!saved) {
|
|
334
|
+
throw new Error(project.LatestResult?.CompleteMessage || 'Failed to move folder');
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
finally {
|
|
338
|
+
this._selfMutating = false;
|
|
339
|
+
}
|
|
340
|
+
this._projects$.next([...this._projects$.value]);
|
|
341
|
+
return true;
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Deletes a folder (project) in an FK-safe way. The Conversation→Project and
|
|
345
|
+
* Project→Project (ParentID) foreign keys are RESTRICT, so the row can't be
|
|
346
|
+
* deleted while anything references it. Before deleting, this:
|
|
347
|
+
* 1. Unassigns every conversation directly in the folder (ProjectID → null).
|
|
348
|
+
* 2. Reparents direct child folders to this folder's parent (one level up).
|
|
349
|
+
* 3. Deletes the now-unreferenced folder.
|
|
350
|
+
* Conversations and subfolders are preserved — only the folder itself is removed.
|
|
351
|
+
*
|
|
352
|
+
* Note: this does NOT reassign Tasks that reference the project; if a Task still
|
|
353
|
+
* references it, the final delete will fail and this throws with the DB message.
|
|
354
|
+
*
|
|
355
|
+
* @param id - The project (folder) ID to delete
|
|
356
|
+
* @param contextUser - The current user context
|
|
357
|
+
* @returns true if deleted successfully
|
|
358
|
+
*/
|
|
359
|
+
async DeleteProject(id, contextUser) {
|
|
360
|
+
const md = this.ProviderToUse;
|
|
361
|
+
// 1. Unassign conversations directly in this folder
|
|
362
|
+
const directConversations = this._conversations$.value.filter(c => c.ProjectID && UUIDsEqual(c.ProjectID, id));
|
|
363
|
+
for (const conv of directConversations) {
|
|
364
|
+
await this.SaveConversation(conv.ID, { ProjectID: null }, contextUser);
|
|
365
|
+
}
|
|
366
|
+
// 2. Reparent direct child folders to this folder's parent
|
|
367
|
+
const target = this._projects$.value.find(p => UUIDsEqual(p.ID, id));
|
|
368
|
+
const newParentId = target?.ParentID ?? null;
|
|
369
|
+
const childFolders = this._projects$.value.filter(p => p.ParentID && UUIDsEqual(p.ParentID, id));
|
|
370
|
+
if (childFolders.length > 0) {
|
|
371
|
+
this._selfMutating = true;
|
|
372
|
+
try {
|
|
373
|
+
for (const child of childFolders) {
|
|
374
|
+
child.ParentID = newParentId;
|
|
375
|
+
const saved = await child.Save();
|
|
376
|
+
if (!saved) {
|
|
377
|
+
throw new Error(child.LatestResult?.CompleteMessage || 'Failed to reparent subfolder');
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
finally {
|
|
382
|
+
this._selfMutating = false;
|
|
383
|
+
}
|
|
384
|
+
// Children were mutated in place — re-emit so subscribers re-read the tree
|
|
385
|
+
this._projects$.next([...this._projects$.value]);
|
|
386
|
+
}
|
|
387
|
+
// 3. Delete the now-unreferenced folder
|
|
388
|
+
let project = target;
|
|
389
|
+
if (!project) {
|
|
390
|
+
project = await md.GetEntityObject('MJ: Projects', contextUser);
|
|
391
|
+
const loaded = await project.Load(id);
|
|
392
|
+
if (!loaded) {
|
|
393
|
+
throw new Error('Folder not found');
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
// Remove from the cached list BEFORE calling Delete(). BaseEntity.Delete() calls
|
|
397
|
+
// NewRecord() which wipes the entity's fields — including ID — so filtering the list
|
|
398
|
+
// by ID *after* the delete wouldn't match the (now-blank) cached entity and the folder
|
|
399
|
+
// would linger until a manual refresh. Capture the pre-delete array so we can restore
|
|
400
|
+
// it if the delete fails.
|
|
401
|
+
const projectsBeforeDelete = this._projects$.value;
|
|
402
|
+
this._projects$.next(projectsBeforeDelete.filter(p => !UUIDsEqual(p.ID, id)));
|
|
403
|
+
this._selfMutating = true;
|
|
404
|
+
let deleted = false;
|
|
405
|
+
try {
|
|
406
|
+
deleted = await project.Delete();
|
|
407
|
+
}
|
|
408
|
+
finally {
|
|
409
|
+
this._selfMutating = false;
|
|
410
|
+
}
|
|
411
|
+
if (!deleted) {
|
|
412
|
+
// Restore the list on failure (the entity wasn't deleted, so its fields are intact)
|
|
413
|
+
this._projects$.next(projectsBeforeDelete);
|
|
414
|
+
throw new Error(project.LatestResult?.CompleteMessage || 'Failed to delete folder');
|
|
415
|
+
}
|
|
416
|
+
return true;
|
|
417
|
+
}
|
|
243
418
|
/**
|
|
244
419
|
* Creates a new conversation, saves it to the database, and adds it to the cached list.
|
|
245
420
|
*
|
|
@@ -874,8 +1049,10 @@ export class ConversationEngine extends BaseEngine {
|
|
|
874
1049
|
*/
|
|
875
1050
|
ClearCache() {
|
|
876
1051
|
this._conversations$.next([]);
|
|
1052
|
+
this._projects$.next([]);
|
|
877
1053
|
this._detailCache.clear();
|
|
878
1054
|
this._lastEnvironmentId = null;
|
|
1055
|
+
this._lastProjectsEnvironmentId = null;
|
|
879
1056
|
}
|
|
880
1057
|
// ========================================================================
|
|
881
1058
|
// CONVERSATION DETAIL CRUD
|
|
@@ -1005,6 +1182,9 @@ export class ConversationEngine extends BaseEngine {
|
|
|
1005
1182
|
if (normalizedName === 'mj: conversation details') {
|
|
1006
1183
|
return this.handleConversationDetailEntityEvent(event, effectiveType);
|
|
1007
1184
|
}
|
|
1185
|
+
if (normalizedName === 'mj: projects') {
|
|
1186
|
+
return this.handleProjectEntityEvent(event, effectiveType);
|
|
1187
|
+
}
|
|
1008
1188
|
if (normalizedName === 'mj: ai agent runs') {
|
|
1009
1189
|
return this.handleAgentRunEntityEvent(event, effectiveType);
|
|
1010
1190
|
}
|
|
@@ -1113,6 +1293,45 @@ export class ConversationEngine extends BaseEngine {
|
|
|
1113
1293
|
}
|
|
1114
1294
|
return true;
|
|
1115
1295
|
}
|
|
1296
|
+
/**
|
|
1297
|
+
* Handles save/delete events on Project entities from local or remote code.
|
|
1298
|
+
* Keeps the folder list in sync when a folder is created, renamed, archived, or
|
|
1299
|
+
* deleted via the project form modal. Only tracks projects in the currently-loaded
|
|
1300
|
+
* environment; archived projects are dropped from the active list.
|
|
1301
|
+
*/
|
|
1302
|
+
handleProjectEntityEvent(event, action) {
|
|
1303
|
+
const data = this.extractRecordData(event);
|
|
1304
|
+
const id = data?.['ID'];
|
|
1305
|
+
if (!id)
|
|
1306
|
+
return true;
|
|
1307
|
+
const current = this._projects$.value;
|
|
1308
|
+
const existingIdx = current.findIndex(p => UUIDsEqual(p.ID, id));
|
|
1309
|
+
if (action === 'delete') {
|
|
1310
|
+
if (existingIdx >= 0) {
|
|
1311
|
+
this._projects$.next(current.filter(p => !UUIDsEqual(p.ID, id)));
|
|
1312
|
+
}
|
|
1313
|
+
return true;
|
|
1314
|
+
}
|
|
1315
|
+
// save — only track projects in the loaded environment; drop archived ones
|
|
1316
|
+
const environmentId = data?.['EnvironmentID'];
|
|
1317
|
+
const isArchived = data?.['IsArchived'] === true;
|
|
1318
|
+
const inLoadedEnvironment = !this._lastProjectsEnvironmentId ||
|
|
1319
|
+
(environmentId != null && UUIDsEqual(environmentId, this._lastProjectsEnvironmentId));
|
|
1320
|
+
if (existingIdx >= 0) {
|
|
1321
|
+
if (isArchived || !inLoadedEnvironment) {
|
|
1322
|
+
this._projects$.next(current.filter(p => !UUIDsEqual(p.ID, id)));
|
|
1323
|
+
}
|
|
1324
|
+
else {
|
|
1325
|
+
this.mergeDataOntoRecord(current[existingIdx], data);
|
|
1326
|
+
this._projects$.next([...current]);
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
else if (event.baseEntity && !isArchived && inLoadedEnvironment) {
|
|
1330
|
+
// New folder from a local event — append the entity object
|
|
1331
|
+
this._projects$.next([...current, event.baseEntity]);
|
|
1332
|
+
}
|
|
1333
|
+
return true;
|
|
1334
|
+
}
|
|
1116
1335
|
/**
|
|
1117
1336
|
* Handles save/delete events on AI Agent Run entities from local or remote code.
|
|
1118
1337
|
* Updates the AgentRunsByDetailId map so timers and status reflect reality.
|