@memberjunction/server 2.32.1 → 2.33.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/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js +78 -66
- package/dist/generic/ResolverBase.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -1
- package/dist/resolvers/ActionResolver.d.ts +49 -0
- package/dist/resolvers/ActionResolver.d.ts.map +1 -0
- package/dist/resolvers/ActionResolver.js +359 -0
- package/dist/resolvers/ActionResolver.js.map +1 -0
- package/dist/resolvers/GetDataContextDataResolver.d.ts +1 -1
- package/dist/resolvers/GetDataContextDataResolver.d.ts.map +1 -1
- package/dist/resolvers/GetDataContextDataResolver.js +1 -1
- package/dist/resolvers/GetDataContextDataResolver.js.map +1 -1
- package/package.json +24 -22
- package/src/generic/ResolverBase.ts +117 -78
- package/src/index.ts +22 -0
- package/src/resolvers/ActionResolver.ts +547 -0
- package/src/resolvers/GetDataContextDataResolver.ts +2 -2
|
@@ -0,0 +1,547 @@
|
|
|
1
|
+
import { Resolver, Mutation, Arg, Ctx } from "type-graphql";
|
|
2
|
+
import { ActionEngineServer } from "@memberjunction/actions";
|
|
3
|
+
import { EntityActionEngineServer } from "@memberjunction/actions";
|
|
4
|
+
import { Metadata, UserInfo, BaseEntity, CompositeKey, KeyValuePair, LogError } from "@memberjunction/core";
|
|
5
|
+
import { ActionParam } from "@memberjunction/actions-base";
|
|
6
|
+
import { Field, InputType, ObjectType } from "type-graphql";
|
|
7
|
+
import { KeyValuePairInput } from "../generic/KeyValuePairInput";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Input type for action parameters
|
|
11
|
+
* Used to pass parameters to actions when invoking them
|
|
12
|
+
*/
|
|
13
|
+
@InputType()
|
|
14
|
+
export class ActionParamInput {
|
|
15
|
+
/**
|
|
16
|
+
* The name of the parameter
|
|
17
|
+
*/
|
|
18
|
+
@Field()
|
|
19
|
+
Name: string;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The value of the parameter
|
|
23
|
+
* Complex objects should be serialized to JSON strings
|
|
24
|
+
*/
|
|
25
|
+
@Field({ nullable: true })
|
|
26
|
+
Value: string;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The data type of the parameter
|
|
30
|
+
* Used for type conversion on the server
|
|
31
|
+
*/
|
|
32
|
+
@Field()
|
|
33
|
+
Type: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Input type for running an action
|
|
38
|
+
*/
|
|
39
|
+
@InputType()
|
|
40
|
+
export class RunActionInput {
|
|
41
|
+
/**
|
|
42
|
+
* The ID of the action to run
|
|
43
|
+
*/
|
|
44
|
+
@Field()
|
|
45
|
+
ActionID: string;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Parameters to pass to the action
|
|
49
|
+
*/
|
|
50
|
+
@Field(() => [ActionParamInput], { nullable: true })
|
|
51
|
+
Params?: ActionParamInput[];
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Whether to skip logging the action execution
|
|
55
|
+
* Defaults to false
|
|
56
|
+
*/
|
|
57
|
+
@Field(() => Boolean, { nullable: true })
|
|
58
|
+
SkipActionLog?: boolean;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Represents a collection of key-value pairs that make up a composite key
|
|
63
|
+
* Used for both primary keys and foreign keys
|
|
64
|
+
*/
|
|
65
|
+
@InputType()
|
|
66
|
+
export class CompositeKeyInput {
|
|
67
|
+
/**
|
|
68
|
+
* The collection of key-value pairs that make up the composite key
|
|
69
|
+
*/
|
|
70
|
+
@Field(() => [KeyValuePairInput])
|
|
71
|
+
KeyValuePairs: KeyValuePairInput[];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Input type for running entity actions
|
|
76
|
+
*/
|
|
77
|
+
@InputType()
|
|
78
|
+
export class EntityActionInput {
|
|
79
|
+
/**
|
|
80
|
+
* The ID of the entity action to run
|
|
81
|
+
*/
|
|
82
|
+
@Field()
|
|
83
|
+
EntityActionID: string;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* The type of invocation (SingleRecord, View, List, etc.)
|
|
87
|
+
*/
|
|
88
|
+
@Field()
|
|
89
|
+
InvocationType: string;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* The name of the entity
|
|
93
|
+
* This is the preferred way to identify an entity as it's more human-readable than EntityID
|
|
94
|
+
*/
|
|
95
|
+
@Field(() => String, { nullable: true })
|
|
96
|
+
EntityName?: string;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* The ID of the entity
|
|
100
|
+
* Use EntityName instead when possible for better code readability
|
|
101
|
+
* @deprecated Use EntityName instead when possible
|
|
102
|
+
*/
|
|
103
|
+
@Field(() => String, { nullable: true })
|
|
104
|
+
EntityID?: string;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* The primary key of the entity record to act on
|
|
108
|
+
* This is used for SingleRecord invocation types
|
|
109
|
+
*/
|
|
110
|
+
@Field(() => CompositeKeyInput, { nullable: true })
|
|
111
|
+
PrimaryKey?: CompositeKeyInput;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* The ID of the list to operate on
|
|
115
|
+
* This is used for List invocation types
|
|
116
|
+
*/
|
|
117
|
+
@Field(() => String, { nullable: true })
|
|
118
|
+
ListID?: string;
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* The ID of the view to operate on
|
|
122
|
+
* This is used for View invocation types
|
|
123
|
+
*/
|
|
124
|
+
@Field(() => String, { nullable: true })
|
|
125
|
+
ViewID?: string;
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Additional parameters to pass to the action
|
|
129
|
+
*/
|
|
130
|
+
@Field(() => [ActionParamInput], { nullable: true })
|
|
131
|
+
Params?: ActionParamInput[];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Output type for action results
|
|
136
|
+
* Used to return results from actions to clients
|
|
137
|
+
*/
|
|
138
|
+
@ObjectType()
|
|
139
|
+
export class ActionResultOutput {
|
|
140
|
+
/**
|
|
141
|
+
* Whether the action was executed successfully
|
|
142
|
+
*/
|
|
143
|
+
@Field()
|
|
144
|
+
Success: boolean;
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Optional message describing the result of the action
|
|
148
|
+
*/
|
|
149
|
+
@Field({ nullable: true })
|
|
150
|
+
Message?: string;
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Optional result code from the action
|
|
154
|
+
*/
|
|
155
|
+
@Field(() => String, { nullable: true })
|
|
156
|
+
ResultCode?: string;
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Optional result data from the action
|
|
160
|
+
* Complex objects are serialized to JSON strings
|
|
161
|
+
*/
|
|
162
|
+
@Field(() => String, { nullable: true })
|
|
163
|
+
ResultData?: string;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Resolver for action-related GraphQL operations
|
|
168
|
+
* Handles running actions and entity actions through GraphQL
|
|
169
|
+
*/
|
|
170
|
+
@Resolver()
|
|
171
|
+
export class ActionResolver {
|
|
172
|
+
/**
|
|
173
|
+
* Mutation for running an action
|
|
174
|
+
* @param input The input parameters for running the action
|
|
175
|
+
* @param ctx The GraphQL context containing user authentication information
|
|
176
|
+
* @returns The result of running the action
|
|
177
|
+
*/
|
|
178
|
+
@Mutation(() => ActionResultOutput)
|
|
179
|
+
async RunAction(
|
|
180
|
+
@Arg("input") input: RunActionInput,
|
|
181
|
+
@Ctx() ctx: any
|
|
182
|
+
): Promise<ActionResultOutput> {
|
|
183
|
+
try {
|
|
184
|
+
// Get the user from context
|
|
185
|
+
const user = this.getUserFromContext(ctx);
|
|
186
|
+
|
|
187
|
+
// Initialize the action engine
|
|
188
|
+
await ActionEngineServer.Instance.Config(false, user);
|
|
189
|
+
|
|
190
|
+
// Get the action by ID
|
|
191
|
+
const action = this.findActionById(input.ActionID);
|
|
192
|
+
|
|
193
|
+
// Parse the parameters
|
|
194
|
+
const params = this.parseActionParameters(input.Params);
|
|
195
|
+
|
|
196
|
+
// Run the action
|
|
197
|
+
const result = await this.executeAction(action, user, params, input.SkipActionLog);
|
|
198
|
+
|
|
199
|
+
// Return the result
|
|
200
|
+
return this.createActionResult(result);
|
|
201
|
+
} catch (e) {
|
|
202
|
+
return this.handleActionError(e);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Finds an action by its ID
|
|
208
|
+
* @param actionID The ID of the action to find
|
|
209
|
+
* @returns The action
|
|
210
|
+
* @throws Error if the action is not found
|
|
211
|
+
* @private
|
|
212
|
+
*/
|
|
213
|
+
private findActionById(actionID: string): any {
|
|
214
|
+
const action = ActionEngineServer.Instance.Actions.find(a => a.ID === actionID);
|
|
215
|
+
if (!action) {
|
|
216
|
+
throw new Error(`Action with ID ${actionID} not found`);
|
|
217
|
+
}
|
|
218
|
+
return action;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Parses action parameters from the input
|
|
223
|
+
* @param inputParams The input parameters
|
|
224
|
+
* @returns The parsed parameters
|
|
225
|
+
* @private
|
|
226
|
+
*/
|
|
227
|
+
private parseActionParameters(inputParams?: ActionParamInput[]): ActionParam[] {
|
|
228
|
+
if (!inputParams || inputParams.length === 0) {
|
|
229
|
+
return [];
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return inputParams.map(p => {
|
|
233
|
+
let value: any = p.Value;
|
|
234
|
+
|
|
235
|
+
// Try to parse JSON for complex values
|
|
236
|
+
try {
|
|
237
|
+
if (p.Value && (p.Type === 'object' || p.Type === 'array')) {
|
|
238
|
+
value = JSON.parse(p.Value);
|
|
239
|
+
}
|
|
240
|
+
} catch (e) {
|
|
241
|
+
// If parsing fails, keep the original value
|
|
242
|
+
const error = e as Error;
|
|
243
|
+
LogError(`Failed to parse parameter value as JSON: ${error.message}`);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return {
|
|
247
|
+
Name: p.Name,
|
|
248
|
+
Value: value,
|
|
249
|
+
Type: 'Input' // Default to Input type since we're sending parameters
|
|
250
|
+
};
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Executes an action
|
|
256
|
+
* @param action The action to execute
|
|
257
|
+
* @param user The user context
|
|
258
|
+
* @param params The action parameters
|
|
259
|
+
* @param skipActionLog Whether to skip action logging
|
|
260
|
+
* @returns The action result
|
|
261
|
+
* @private
|
|
262
|
+
*/
|
|
263
|
+
private async executeAction(
|
|
264
|
+
action: any,
|
|
265
|
+
user: UserInfo,
|
|
266
|
+
params: ActionParam[],
|
|
267
|
+
skipActionLog?: boolean
|
|
268
|
+
): Promise<any> {
|
|
269
|
+
return await ActionEngineServer.Instance.RunAction({
|
|
270
|
+
Action: action,
|
|
271
|
+
ContextUser: user,
|
|
272
|
+
Params: params,
|
|
273
|
+
SkipActionLog: skipActionLog,
|
|
274
|
+
Filters: []
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Creates an action result from the execution result
|
|
280
|
+
* @param result The execution result
|
|
281
|
+
* @returns The formatted action result
|
|
282
|
+
* @private
|
|
283
|
+
*/
|
|
284
|
+
private createActionResult(result: any): ActionResultOutput {
|
|
285
|
+
return {
|
|
286
|
+
Success: result.Success,
|
|
287
|
+
Message: result.Message,
|
|
288
|
+
ResultCode: result.Result?.ResultCode,
|
|
289
|
+
ResultData: result.Result ? JSON.stringify(result.Result) : undefined
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Handles errors in the action resolver
|
|
295
|
+
* @param e The error
|
|
296
|
+
* @returns An error result
|
|
297
|
+
* @private
|
|
298
|
+
*/
|
|
299
|
+
private handleActionError(e: unknown): ActionResultOutput {
|
|
300
|
+
const error = e as Error;
|
|
301
|
+
LogError(`Error in RunAction resolver: ${error}`);
|
|
302
|
+
return {
|
|
303
|
+
Success: false,
|
|
304
|
+
Message: `Error executing action: ${error.message}`
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Mutation for running an entity action
|
|
310
|
+
* @param input The input parameters for running the entity action
|
|
311
|
+
* @param ctx The GraphQL context containing user authentication information
|
|
312
|
+
* @returns The result of running the entity action
|
|
313
|
+
*/
|
|
314
|
+
@Mutation(() => ActionResultOutput)
|
|
315
|
+
async RunEntityAction(
|
|
316
|
+
@Arg("input") input: EntityActionInput,
|
|
317
|
+
@Ctx() ctx: any
|
|
318
|
+
): Promise<ActionResultOutput> {
|
|
319
|
+
try {
|
|
320
|
+
// Get the user from context
|
|
321
|
+
const user = this.getUserFromContext(ctx);
|
|
322
|
+
|
|
323
|
+
// Initialize the entity action engine
|
|
324
|
+
await EntityActionEngineServer.Instance.Config(false, user);
|
|
325
|
+
|
|
326
|
+
// Get the entity action by ID
|
|
327
|
+
const entityAction = this.getEntityAction(input.EntityActionID);
|
|
328
|
+
|
|
329
|
+
// Create the base parameters
|
|
330
|
+
const params = this.createBaseParams(entityAction, input.InvocationType, user);
|
|
331
|
+
|
|
332
|
+
// Add entity object if we have entity information and primary key
|
|
333
|
+
if ((input.EntityID || input.EntityName) && input.PrimaryKey && input.PrimaryKey.KeyValuePairs.length > 0) {
|
|
334
|
+
await this.addEntityObject(params, input, user);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Add other parameters
|
|
338
|
+
this.addOptionalParams(params, input);
|
|
339
|
+
|
|
340
|
+
// Run the entity action
|
|
341
|
+
const result = await EntityActionEngineServer.Instance.RunEntityAction(params);
|
|
342
|
+
|
|
343
|
+
// Return the result
|
|
344
|
+
return {
|
|
345
|
+
Success: result.Success,
|
|
346
|
+
Message: result.Message,
|
|
347
|
+
ResultData: JSON.stringify(result)
|
|
348
|
+
};
|
|
349
|
+
} catch (e) {
|
|
350
|
+
return this.handleError(e);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Gets the authenticated user from the GraphQL context
|
|
356
|
+
* @param ctx The GraphQL context
|
|
357
|
+
* @returns The authenticated user
|
|
358
|
+
* @throws Error if user is not authenticated
|
|
359
|
+
* @private
|
|
360
|
+
*/
|
|
361
|
+
private getUserFromContext(ctx: any): UserInfo {
|
|
362
|
+
const user = ctx.user as UserInfo;
|
|
363
|
+
if (!user) {
|
|
364
|
+
throw new Error("User not authenticated");
|
|
365
|
+
}
|
|
366
|
+
return user;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Gets an entity action by ID
|
|
371
|
+
* @param actionID The ID of the entity action
|
|
372
|
+
* @returns The entity action
|
|
373
|
+
* @throws Error if entity action is not found
|
|
374
|
+
* @private
|
|
375
|
+
*/
|
|
376
|
+
private getEntityAction(actionID: string): any {
|
|
377
|
+
const entityAction = EntityActionEngineServer.Instance.EntityActions.find(ea => ea.ID === actionID);
|
|
378
|
+
if (!entityAction) {
|
|
379
|
+
throw new Error(`EntityAction with ID ${actionID} not found`);
|
|
380
|
+
}
|
|
381
|
+
return entityAction;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Creates the base parameters for the entity action
|
|
386
|
+
* @param entityAction The entity action
|
|
387
|
+
* @param invocationTypeName The invocation type name
|
|
388
|
+
* @param user The authenticated user
|
|
389
|
+
* @returns The base parameters
|
|
390
|
+
* @private
|
|
391
|
+
*/
|
|
392
|
+
private createBaseParams(entityAction: any, invocationTypeName: string, user: UserInfo): any {
|
|
393
|
+
return {
|
|
394
|
+
EntityAction: entityAction,
|
|
395
|
+
InvocationType: { Name: invocationTypeName },
|
|
396
|
+
ContextUser: user,
|
|
397
|
+
Params: [],
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Adds the entity object to the parameters
|
|
403
|
+
* @param params The parameters to add to
|
|
404
|
+
* @param input The input parameters
|
|
405
|
+
* @param user The authenticated user
|
|
406
|
+
* @private
|
|
407
|
+
*/
|
|
408
|
+
private async addEntityObject(params: any, input: EntityActionInput, user: UserInfo): Promise<void> {
|
|
409
|
+
const md = new Metadata();
|
|
410
|
+
|
|
411
|
+
// Find the entity by ID or name
|
|
412
|
+
let entity;
|
|
413
|
+
if (input.EntityName) {
|
|
414
|
+
entity = md.Entities.find(e => e.Name === input.EntityName);
|
|
415
|
+
if (!entity) {
|
|
416
|
+
throw new Error(`Entity with name ${input.EntityName} not found`);
|
|
417
|
+
}
|
|
418
|
+
} else if (input.EntityID) {
|
|
419
|
+
entity = md.Entities.find(e => e.ID === input.EntityID);
|
|
420
|
+
if (!entity) {
|
|
421
|
+
throw new Error(`Entity with ID ${input.EntityID} not found`);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
if (!entity) {
|
|
426
|
+
throw new Error("Entity information is required");
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// Create a composite key and load the entity object
|
|
430
|
+
const compositeKey = this.createCompositeKey(entity, input.PrimaryKey);
|
|
431
|
+
const entityObject = await md.GetEntityObject(entity.Name);
|
|
432
|
+
await entityObject.InnerLoad(compositeKey);
|
|
433
|
+
params['EntityObject'] = entityObject;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Creates a composite key from the input
|
|
438
|
+
* @param entity The entity information
|
|
439
|
+
* @param primaryKey The primary key input
|
|
440
|
+
* @returns The composite key
|
|
441
|
+
* @private
|
|
442
|
+
*/
|
|
443
|
+
private createCompositeKey(entity: any, primaryKey: CompositeKeyInput): CompositeKey {
|
|
444
|
+
const compositeKey = new CompositeKey();
|
|
445
|
+
|
|
446
|
+
for (const kvp of primaryKey.KeyValuePairs) {
|
|
447
|
+
// Convert value based on the field type if necessary
|
|
448
|
+
const field = entity.Fields.find(f => f.Name === kvp.Key);
|
|
449
|
+
let value: any = kvp.Value;
|
|
450
|
+
|
|
451
|
+
// If the field is found, try to convert to proper type
|
|
452
|
+
if (field) {
|
|
453
|
+
value = this.convertValueToProperType(value, field);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// Add to composite key
|
|
457
|
+
const kvPair = new KeyValuePair();
|
|
458
|
+
kvPair.FieldName = kvp.Key;
|
|
459
|
+
kvPair.Value = value;
|
|
460
|
+
compositeKey.KeyValuePairs.push(kvPair);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
return compositeKey;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Converts a value to the proper type based on the field information
|
|
468
|
+
* @param value The value to convert
|
|
469
|
+
* @param field The field information
|
|
470
|
+
* @returns The converted value
|
|
471
|
+
* @private
|
|
472
|
+
*/
|
|
473
|
+
private convertValueToProperType(value: any, field: any): any {
|
|
474
|
+
// Simple conversion, could be enhanced for other types
|
|
475
|
+
if (field.Type.toLowerCase().match(/int|decimal|float|money|numeric|real/) && !isNaN(Number(value))) {
|
|
476
|
+
return Number(value);
|
|
477
|
+
} else if (field.Type.toLowerCase().includes('date') && !isNaN(Date.parse(value))) {
|
|
478
|
+
return new Date(value);
|
|
479
|
+
}
|
|
480
|
+
return value;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* Adds optional parameters to the entity action parameters
|
|
485
|
+
* @param params The parameters to add to
|
|
486
|
+
* @param input The input parameters
|
|
487
|
+
* @private
|
|
488
|
+
*/
|
|
489
|
+
private addOptionalParams(params: any, input: EntityActionInput): void {
|
|
490
|
+
// Add list ID if provided
|
|
491
|
+
if (input.ListID) {
|
|
492
|
+
params['ListID'] = input.ListID;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// Add view ID if provided
|
|
496
|
+
if (input.ViewID) {
|
|
497
|
+
params['ViewID'] = input.ViewID;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// Add additional parameters if provided
|
|
501
|
+
if (input.Params && input.Params.length > 0) {
|
|
502
|
+
params.Params = input.Params.map(p => this.convertParameterValue(p));
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* Converts a parameter value to the proper format
|
|
508
|
+
* @param p The parameter to convert
|
|
509
|
+
* @returns The converted parameter
|
|
510
|
+
* @private
|
|
511
|
+
*/
|
|
512
|
+
private convertParameterValue(p: ActionParamInput): any {
|
|
513
|
+
let value: any = p.Value;
|
|
514
|
+
|
|
515
|
+
// Try to parse JSON for complex values
|
|
516
|
+
try {
|
|
517
|
+
if (p.Value && (p.Type === 'object' || p.Type === 'array')) {
|
|
518
|
+
value = JSON.parse(p.Value);
|
|
519
|
+
}
|
|
520
|
+
} catch (e) {
|
|
521
|
+
// If parsing fails, keep the original value
|
|
522
|
+
const error = e as Error;
|
|
523
|
+
LogError(`Failed to parse parameter value as JSON: ${error.message}`);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
return {
|
|
527
|
+
Name: p.Name,
|
|
528
|
+
Value: value,
|
|
529
|
+
Type: 'Input' // Default to Input type since we're sending parameters
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* Handles errors in the entity action resolver
|
|
535
|
+
* @param e The error
|
|
536
|
+
* @returns An error result
|
|
537
|
+
* @private
|
|
538
|
+
*/
|
|
539
|
+
private handleError(e: unknown): ActionResultOutput {
|
|
540
|
+
const error = e as Error;
|
|
541
|
+
LogError(`Error in RunEntityAction resolver: ${error}`);
|
|
542
|
+
return {
|
|
543
|
+
Success: false,
|
|
544
|
+
Message: `Error executing entity action: ${error.message}`
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Arg, Ctx, Field, ObjectType, Query } from "type-graphql";
|
|
2
|
-
import { AppContext } from "../types";
|
|
2
|
+
import { AppContext } from "../types.js";
|
|
3
3
|
import { DataContext } from "@memberjunction/data-context";
|
|
4
|
-
import { GetReadOnlyDataSource } from "../util";
|
|
4
|
+
import { GetReadOnlyDataSource } from "../util.js";
|
|
5
5
|
import { Metadata } from "@memberjunction/core";
|
|
6
6
|
import { DataContextItemEntity } from "@memberjunction/core-entities";
|
|
7
7
|
|