@reqquest/ui 1.0.1 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +8 -0
  2. package/dist/api.js +670 -129
  3. package/dist/components/AppRequestCard.svelte +172 -0
  4. package/dist/components/ApplicantProgramList.svelte +184 -0
  5. package/dist/components/ApplicantProgramListTooltip.svelte +22 -0
  6. package/dist/components/ApplicantPromptPage.svelte +88 -0
  7. package/dist/components/ApplicationDetailsView.svelte +307 -0
  8. package/dist/components/ButtonLoadingIcon.svelte +2 -1
  9. package/dist/components/FieldCardCheckbox.svelte +328 -0
  10. package/dist/components/FieldCardRadio.svelte +320 -0
  11. package/dist/components/IntroPanel.svelte +41 -0
  12. package/dist/components/PeriodPanel.svelte +100 -0
  13. package/dist/components/QuestionnairePrompt.svelte +36 -0
  14. package/dist/components/RenderDisplayComponent.svelte +38 -0
  15. package/dist/components/ReviewerList.svelte +93 -0
  16. package/dist/components/StatusMessageList.svelte +35 -0
  17. package/dist/components/WarningIconYellow.svelte +20 -0
  18. package/dist/components/index.js +11 -0
  19. package/dist/components/types.js +1 -0
  20. package/dist/csv.js +21 -0
  21. package/dist/index.js +2 -1
  22. package/dist/status-utils.js +343 -0
  23. package/dist/typed-client/schema.graphql +619 -134
  24. package/dist/typed-client/schema.js +87 -23
  25. package/dist/typed-client/types.js +993 -482
  26. package/dist/util.js +12 -1
  27. package/package.json +39 -40
  28. package/dist/api.d.ts +0 -595
  29. package/dist/components/ButtonLoadingIcon.svelte.d.ts +0 -18
  30. package/dist/components/index.d.ts +0 -1
  31. package/dist/index.d.ts +0 -5
  32. package/dist/registry.d.ts +0 -138
  33. package/dist/stores/IStateStore.d.ts +0 -5
  34. package/dist/typed-client/index.d.ts +0 -25
  35. package/dist/typed-client/runtime/batcher.d.ts +0 -105
  36. package/dist/typed-client/runtime/createClient.d.ts +0 -17
  37. package/dist/typed-client/runtime/error.d.ts +0 -18
  38. package/dist/typed-client/runtime/fetcher.d.ts +0 -10
  39. package/dist/typed-client/runtime/generateGraphqlOperation.d.ts +0 -30
  40. package/dist/typed-client/runtime/index.d.ts +0 -11
  41. package/dist/typed-client/runtime/linkTypeMap.d.ts +0 -9
  42. package/dist/typed-client/runtime/typeSelection.d.ts +0 -28
  43. package/dist/typed-client/runtime/types.d.ts +0 -55
  44. package/dist/typed-client/schema.d.ts +0 -1483
  45. package/dist/typed-client/types.d.ts +0 -540
  46. package/dist/util.d.ts +0 -2
package/dist/api.js CHANGED
@@ -1,7 +1,11 @@
1
- import { PUBLIC_API_BASE, PUBLIC_AUTH_REDIRECT } from '$env/static/public';
1
+ import { PUBLIC_API_BASE, PUBLIC_AUTH_REDIRECT, PUBLIC_SHOW_DUPLICATE_PROMPTS } from '$env/static/public';
2
2
  import { APIBase } from '@txstate-mws/sveltekit-utils';
3
- import { createClient, enumAppRequestIndexDestination, enumPromptVisibility, enumRequirementType } from './typed-client/index.js';
3
+ import { createClient, enumAppRequestIndexDestination, enumIneligiblePhases, enumPromptVisibility, enumRequirementStatus, enumRequirementType } from './typed-client/index.js';
4
4
  import { DateTime } from 'luxon';
5
+ import { omit, pick } from 'txstate-utils';
6
+ import { error } from '@sveltejs/kit';
7
+ import { applicantRequirementTypes } from './status-utils.js';
8
+ export const showDupePrompts = PUBLIC_SHOW_DUPLICATE_PROMPTS.trim() === 'true';
5
9
  class API extends APIBase {
6
10
  client = createClient({
7
11
  url: PUBLIC_API_BASE,
@@ -16,147 +20,443 @@ class API extends APIBase {
16
20
  const response = await this.client.query({
17
21
  __name: 'GetAccess',
18
22
  access: {
23
+ user: {
24
+ login: true,
25
+ fullname: true
26
+ },
19
27
  createPeriod: true,
20
28
  createRole: true,
21
29
  viewRoleManagement: true,
22
30
  viewPeriodManagement: true,
23
31
  viewReviewerInterface: true,
24
32
  viewApplicantDashboard: true,
25
- viewAppRequestList: true
33
+ viewAppRequestList: true,
34
+ createAppRequestSelf: true,
35
+ createAppRequestOther: true
26
36
  }
27
37
  });
28
38
  return response.access;
29
39
  }
30
- async getApplicantRequests() {
40
+ async getAccessUsers(accessUsersFilter, pageFilter) {
41
+ const filter = accessUsersFilter;
42
+ const paged = pageFilter;
43
+ const response = await this.client.query({
44
+ __name: 'GetAccessUsers',
45
+ accessUsers: {
46
+ __args: { filter, paged },
47
+ login: true,
48
+ fullname: true,
49
+ groups: true,
50
+ roles: {
51
+ name: true
52
+ },
53
+ otherIdentifiers: {
54
+ id: true,
55
+ label: true
56
+ },
57
+ otherInfo: true
58
+ },
59
+ pageInfo: {
60
+ accessUsers: {
61
+ currentPage: true,
62
+ totalItems: true,
63
+ hasNextPage: true,
64
+ perPage: true,
65
+ categories: {
66
+ tags: {
67
+ tag: true,
68
+ label: true
69
+ },
70
+ category: true,
71
+ label: true,
72
+ useInFilters: true,
73
+ useInList: true
74
+ }
75
+ }
76
+ }
77
+ });
78
+ return { users: response.accessUsers, pageInfo: response.pageInfo.accessUsers };
79
+ }
80
+ async getApplicantRequests(additionalFilters = {}, paged) {
81
+ // const filter = { own: true, ...additionalFilters }
82
+ const filter = { ...additionalFilters };
31
83
  const response = await this.client.query({
32
84
  __name: 'GetApplicantRequests',
33
85
  appRequests: {
34
- __args: { filter: { own: true } },
86
+ __args: { filter, paged },
35
87
  id: true,
36
88
  status: true,
89
+ createdAt: true,
90
+ updatedAt: true,
91
+ complete: true,
92
+ applicant: {
93
+ fullname: true,
94
+ otherIdentifiers: {
95
+ id: true
96
+ }
97
+ },
37
98
  period: {
38
99
  name: true,
39
100
  openDate: true,
40
101
  closeDate: true
102
+ },
103
+ applications: {
104
+ id: true,
105
+ title: true,
106
+ status: true,
107
+ statusReason: true,
108
+ requirements: {
109
+ id: true,
110
+ type: true,
111
+ status: true,
112
+ statusReason: true,
113
+ prompts: {
114
+ id: true,
115
+ visibility: true,
116
+ invalidated: true,
117
+ invalidatedReason: true
118
+ }
119
+ }
120
+ },
121
+ actions: {
122
+ acceptOffer: true,
123
+ cancel: true,
124
+ reopen: true,
125
+ returnToApplicant: true,
126
+ returnToOffer: true,
127
+ submit: true
41
128
  }
42
129
  }
43
130
  });
44
131
  return response.appRequests;
45
132
  }
46
- async getNextPrompt(appRequestId, currentPromptKey) {
133
+ async getApplicantPrompt(appRequestId, promptId) {
47
134
  const response = await this.client.query({
48
- __name: 'GetNextPrompt',
135
+ __name: 'GetPromptData',
49
136
  appRequests: {
50
137
  __args: { filter: { ids: [appRequestId] } },
138
+ data: true,
139
+ dataVersion: true,
51
140
  applications: {
141
+ id: true,
52
142
  requirements: {
143
+ type: true,
144
+ status: true,
145
+ statusReason: true,
53
146
  prompts: {
54
147
  id: true,
55
148
  key: true,
149
+ title: true,
150
+ description: true,
56
151
  answered: true,
57
- visibility: true
152
+ visibility: true,
153
+ preloadData: true,
154
+ fetchedData: true,
155
+ configurationData: true,
156
+ gatheredConfigData: true
58
157
  }
59
158
  }
60
159
  }
61
160
  }
62
161
  });
63
- let currentKeyFound = false;
64
- for (const applications of response.appRequests[0]?.applications ?? []) {
65
- for (const requirement of applications.requirements) {
162
+ if (response.appRequests.length === 0)
163
+ return {};
164
+ const appRequest = response.appRequests[0];
165
+ for (const application of appRequest.applications) {
166
+ for (const requirement of application.requirements.filter(r => applicantRequirementTypes.has(r.type))) {
66
167
  for (const prompt of requirement.prompts) {
67
- if ((!prompt.answered || currentKeyFound) && prompt.visibility === enumPromptVisibility.AVAILABLE)
68
- return prompt;
69
- if (prompt.key === currentPromptKey && prompt.visibility === enumPromptVisibility.AVAILABLE)
70
- currentKeyFound = true;
168
+ if (prompt.id === promptId)
169
+ return { prompt };
71
170
  }
72
171
  }
73
172
  }
173
+ return {};
74
174
  }
75
- async getApplyNavigation(appRequestId) {
175
+ async updatePrompt(promptId, data, validateOnly, dataVersion) {
176
+ const response = await this.graphqlWithUploads(`
177
+ mutation UpdatePrompt($promptId: ID!, $data: JsonData!, $validateOnly: Boolean!, $dataVersion: Int) {
178
+ updatePrompt(promptId: $promptId, data: $data, validateOnly: $validateOnly, dataVersion: $dataVersion) {
179
+ success
180
+ messages {
181
+ message
182
+ type
183
+ arg
184
+ }
185
+ }
186
+ }
187
+ `, { promptId, data, validateOnly, dataVersion });
188
+ return this.mutationForDialog(response.updatePrompt);
189
+ }
190
+ async updateConfiguration(periodId, definitionKey, data, validateOnly) {
191
+ const response = await this.client.mutation({
192
+ __name: 'UpdateConfiguration',
193
+ updateConfiguration: {
194
+ __args: { periodId, key: definitionKey, data, validateOnly },
195
+ success: true,
196
+ messages: {
197
+ message: true,
198
+ type: true,
199
+ arg: true
200
+ }
201
+ }
202
+ });
203
+ return this.mutationForDialog(response.updateConfiguration);
204
+ }
205
+ async getAppRequestData(appRequestId) {
76
206
  const response = await this.client.query({
77
- __name: 'GetApplyNavigation',
207
+ __name: 'GetAppRequestData',
78
208
  appRequests: {
79
209
  __args: { filter: { ids: [appRequestId] } },
80
210
  id: true,
81
- status: true,
211
+ data: true,
82
212
  applications: {
83
- id: true,
84
- status: true,
85
- statusReason: true,
86
- title: true,
87
- navTitle: true,
88
213
  requirements: {
89
- id: true,
90
- type: true,
91
- status: true,
92
- statusReason: true,
93
214
  prompts: {
94
- id: true,
95
215
  key: true,
96
- title: true,
97
- navTitle: true,
98
- answered: true,
99
- visibility: true
216
+ gatheredConfigData: true
100
217
  }
101
218
  }
102
219
  }
103
220
  }
104
221
  });
105
222
  if (response.appRequests.length === 0)
106
- return { prequalPrompts: [], appRequest: undefined };
223
+ return { data: {}, applications: [] };
107
224
  const appRequest = response.appRequests[0];
108
- const prequalPrompts = appRequest.applications.flatMap(application => application.requirements.filter(r => r.type === enumRequirementType.PREQUAL).flatMap(r => r.prompts.filter(p => p.visibility === enumPromptVisibility.AVAILABLE)));
109
- const postqualPrompts = appRequest.applications.flatMap(application => application.requirements.filter(r => r.type === enumRequirementType.POSTQUAL).flatMap(r => r.prompts.filter(p => p.visibility === enumPromptVisibility.AVAILABLE)));
110
- const applications = appRequest.applications.map(application => ({
111
- ...application,
112
- requirements: application.requirements.filter(r => r.type === enumRequirementType.QUALIFICATION).map(requirement => ({
113
- ...requirement,
114
- prompts: requirement.prompts.filter(p => p.visibility === enumPromptVisibility.AVAILABLE)
115
- }))
116
- }));
117
- return { prequalPrompts, postqualPrompts, appRequest: { ...appRequest, applications } };
118
- }
119
- async getApplicantPrompt(appRequestId, promptKey) {
225
+ return appRequest;
226
+ }
227
+ static splitPromptsForApplicant(applications) {
228
+ const prequalPrompts = [];
229
+ const postqualPrompts = [];
230
+ const qualPrompts = [];
231
+ const applicationsReviewWithDupes = [];
232
+ const applicationsReviewNoDupes = [];
233
+ const applicationsForNavWithDupes = [];
234
+ const applicationsForNavNoDupes = [];
235
+ const applicationsAcceptWithDupes = [];
236
+ const applicationsAcceptNoDupes = [];
237
+ const promptsById = {};
238
+ const promptsByKey = {};
239
+ const seenForReview = new Set();
240
+ const seenForNav = new Set();
241
+ const seenForAccept = new Set();
242
+ const visibilitiesToShow = new Set([enumPromptVisibility.AVAILABLE, enumPromptVisibility.REQUEST_DUPE]);
243
+ const requirementTypesForNavigation = new Set([enumRequirementType.PREQUAL, enumRequirementType.POSTQUAL, enumRequirementType.QUALIFICATION]);
244
+ const requirementTypesForReview = new Set([enumRequirementType.QUALIFICATION, enumRequirementType.PREAPPROVAL, enumRequirementType.APPROVAL, enumRequirementType.WORKFLOW]);
245
+ for (const application of applications) {
246
+ const requirementsReviewWithDupes = [];
247
+ const requirementsReviewNoDupes = [];
248
+ const requirementsForNavWithDupes = [];
249
+ const requirementsForNavNoDupes = [];
250
+ const requirementsAcceptWithDupes = [];
251
+ const requirementsAcceptNoDupes = [];
252
+ for (const requirement of application.requirements) {
253
+ const promptsForNavWithDupes = [];
254
+ const promptsForNavNoDupes = [];
255
+ const promptsReviewNoDupes = [];
256
+ const promptsReviewWithDupes = [];
257
+ const promptsAcceptWithDupes = [];
258
+ const promptsAcceptNoDupes = [];
259
+ for (const prompt of requirement.prompts) {
260
+ const retPrompt = { ...prompt, statusReasons: [{ ...pick(requirement, 'status', 'statusReason'), programName: application.title }] };
261
+ const withDupesPrompt = { ...retPrompt };
262
+ promptsById[prompt.id] = retPrompt;
263
+ if (prompt.moot || prompt.visibility === enumPromptVisibility.UNREACHABLE)
264
+ continue;
265
+ promptsByKey[prompt.key] ??= [];
266
+ promptsByKey[prompt.key].push(retPrompt);
267
+ if (!visibilitiesToShow.has(prompt.visibility))
268
+ continue;
269
+ promptsReviewWithDupes.push(withDupesPrompt);
270
+ if (requirementTypesForNavigation.has(requirement.type))
271
+ promptsForNavWithDupes.push(withDupesPrompt);
272
+ if (requirement.type === enumRequirementType.ACCEPTANCE)
273
+ promptsAcceptWithDupes.push(withDupesPrompt);
274
+ if (!seenForReview.has(prompt.key))
275
+ promptsReviewNoDupes.push(retPrompt);
276
+ seenForReview.add(prompt.key);
277
+ if (requirementTypesForNavigation.has(requirement.type)) {
278
+ if (!seenForNav.has(prompt.key))
279
+ promptsForNavNoDupes.push(retPrompt);
280
+ seenForNav.add(prompt.key);
281
+ }
282
+ if (requirement.type === enumRequirementType.ACCEPTANCE) {
283
+ if (!seenForAccept.has(prompt.key))
284
+ promptsAcceptNoDupes.push(retPrompt);
285
+ seenForAccept.add(prompt.key);
286
+ }
287
+ }
288
+ if (requirement.type === enumRequirementType.PREQUAL)
289
+ prequalPrompts.push(...promptsForNavNoDupes);
290
+ else if (requirement.type === enumRequirementType.POSTQUAL)
291
+ postqualPrompts.push(...promptsForNavNoDupes);
292
+ else if (requirementTypesForReview.has(requirement.type)) {
293
+ requirementsReviewWithDupes.push({ ...requirement, prompts: promptsReviewWithDupes });
294
+ requirementsReviewNoDupes.push({ ...requirement, prompts: promptsReviewNoDupes });
295
+ if (requirement.type === enumRequirementType.QUALIFICATION) {
296
+ qualPrompts.push(...promptsForNavNoDupes);
297
+ requirementsForNavWithDupes.push({ ...requirement, prompts: promptsForNavWithDupes });
298
+ requirementsForNavNoDupes.push({ ...requirement, prompts: promptsForNavNoDupes });
299
+ }
300
+ }
301
+ else if (requirement.type === enumRequirementType.ACCEPTANCE) {
302
+ requirementsAcceptWithDupes.push({ ...requirement, prompts: promptsAcceptWithDupes });
303
+ requirementsAcceptNoDupes.push({ ...requirement, prompts: promptsAcceptNoDupes });
304
+ }
305
+ }
306
+ const reqsForCompletion = application.requirements.filter(r => r.type !== enumRequirementType.POSTQUAL);
307
+ let completionStatus = 'ELIGIBLE';
308
+ let completionStatusForNav = 'ELIGIBLE';
309
+ const warningReasons = [];
310
+ const warningReasonsFull = [];
311
+ const ineligibleReasons = [];
312
+ const ineligibleReasonsFull = [];
313
+ let hasWarning = false;
314
+ let hasWarningForNav = false;
315
+ for (const req of reqsForCompletion) {
316
+ const showWarnings = application.ineligiblePhase !== enumIneligiblePhases.PREQUAL || req.type === enumRequirementType.PREQUAL;
317
+ if (req.status === enumRequirementStatus.PENDING) {
318
+ if (completionStatus !== 'INELIGIBLE')
319
+ completionStatus = 'PENDING';
320
+ if (completionStatusForNav !== 'INELIGIBLE' && requirementTypesForNavigation.has(req.type))
321
+ completionStatusForNav = 'PENDING';
322
+ }
323
+ else if (req.status === enumRequirementStatus.WARNING) {
324
+ hasWarning = true;
325
+ if (requirementTypesForNavigation.has(req.type))
326
+ hasWarningForNav = true;
327
+ if (req.statusReason && showWarnings) {
328
+ if (requirementTypesForNavigation.has(req.type))
329
+ warningReasons.push(req.statusReason);
330
+ warningReasonsFull.push(req.statusReason);
331
+ }
332
+ }
333
+ else if (req.status === enumRequirementStatus.DISQUALIFYING) {
334
+ completionStatus = 'INELIGIBLE';
335
+ if (requirementTypesForNavigation.has(req.type))
336
+ completionStatusForNav = 'INELIGIBLE';
337
+ if (req.statusReason && showWarnings) {
338
+ if (requirementTypesForNavigation.has(req.type))
339
+ ineligibleReasons.push(req.statusReason);
340
+ if (application.ineligiblePhase !== enumIneligiblePhases.PREQUAL || req.type !== enumRequirementType.PREQUAL)
341
+ ineligibleReasonsFull.push(req.statusReason);
342
+ }
343
+ }
344
+ }
345
+ applicationsReviewWithDupes.push({ ...application, requirements: requirementsReviewWithDupes, completionStatus, warningReasons: warningReasonsFull, ineligibleReasons: ineligibleReasonsFull, hasWarning });
346
+ applicationsReviewNoDupes.push({ ...application, requirements: requirementsReviewNoDupes, completionStatus, warningReasons: warningReasonsFull, ineligibleReasons: ineligibleReasonsFull, hasWarning });
347
+ applicationsForNavWithDupes.push({ ...application, requirements: requirementsForNavWithDupes, completionStatus: completionStatusForNav, warningReasons, ineligibleReasons, hasWarning: hasWarningForNav });
348
+ applicationsForNavNoDupes.push({ ...application, requirements: requirementsForNavNoDupes, completionStatus: completionStatusForNav, warningReasons, ineligibleReasons, hasWarning: hasWarningForNav });
349
+ applicationsAcceptWithDupes.push({ ...application, requirements: requirementsAcceptWithDupes, completionStatus, warningReasons: warningReasonsFull, ineligibleReasons: ineligibleReasonsFull, hasWarning });
350
+ applicationsAcceptNoDupes.push({ ...application, requirements: requirementsAcceptNoDupes, completionStatus, warningReasons: warningReasonsFull, ineligibleReasons: ineligibleReasonsFull, hasWarning });
351
+ }
352
+ for (const prompts of Object.values(promptsByKey)) {
353
+ const statusReasons = prompts.map(p => p.statusReasons[0]);
354
+ for (const prompt of prompts)
355
+ prompt.statusReasons = statusReasons;
356
+ }
357
+ return { prequalPrompts, postqualPrompts, qualPrompts, applicationsReviewWithDupes, applicationsReviewNoDupes, applicationsForNavWithDupes, applicationsForNavNoDupes, applicationsAcceptWithDupes, applicationsAcceptNoDupes, promptsByKey, promptsById };
358
+ }
359
+ async getAppRequestForExport(appRequestId) {
120
360
  const response = await this.client.query({
121
- __name: 'GetPromptData',
361
+ __name: 'GetAppRequestForExport',
122
362
  appRequests: {
123
363
  __args: { filter: { ids: [appRequestId] } },
364
+ id: true,
365
+ status: true,
124
366
  data: true,
367
+ dataVersion: true,
368
+ period: {
369
+ name: true
370
+ },
125
371
  applications: {
126
372
  id: true,
373
+ status: true,
374
+ ineligiblePhase: true,
375
+ statusReason: true,
376
+ title: true,
377
+ navTitle: true,
127
378
  requirements: {
379
+ id: true,
128
380
  type: true,
129
381
  status: true,
130
382
  statusReason: true,
131
383
  prompts: {
132
384
  id: true,
133
385
  key: true,
386
+ title: true,
387
+ navTitle: true,
388
+ answered: true,
134
389
  visibility: true,
135
- fetchedData: true,
136
- configurationRelatedData: true
390
+ moot: true,
391
+ invalidated: true,
392
+ invalidatedReason: true,
393
+ configurationData: true,
394
+ gatheredConfigData: true
137
395
  }
138
396
  }
397
+ },
398
+ actions: {
399
+ viewApplyUI: true,
400
+ viewAcceptUI: true
139
401
  }
140
402
  }
141
403
  });
142
404
  if (response.appRequests.length === 0)
143
- return {};
144
- const appRequest = response.appRequests[0];
145
- for (const application of appRequest.applications) {
146
- for (const requirement of application.requirements.filter(r => r.type === enumRequirementType.PREQUAL || r.type === enumRequirementType.QUALIFICATION || r.type === enumRequirementType.POSTQUAL)) {
147
- for (const prompt of requirement.prompts) {
148
- if (prompt.key === promptKey && prompt.visibility === enumPromptVisibility.AVAILABLE)
149
- return { appRequestData: appRequest.data, prompt };
405
+ throw error(404, 'Application request not found');
406
+ const splitInfo = API.splitPromptsForApplicant(response.appRequests[0]?.applications ?? []);
407
+ return {
408
+ ...omit(splitInfo, 'applicationsForNavNoDupes', 'applicationsForNavWithDupes', 'applicationsReviewNoDupes', 'applicationsReviewWithDupes'),
409
+ applicationsForNav: showDupePrompts ? splitInfo.applicationsForNavWithDupes : splitInfo.applicationsForNavNoDupes,
410
+ applicationsReview: showDupePrompts ? splitInfo.applicationsReviewWithDupes : splitInfo.applicationsReviewNoDupes,
411
+ applicationsAccept: showDupePrompts ? splitInfo.applicationsAcceptWithDupes : splitInfo.applicationsAcceptNoDupes,
412
+ appRequest: response.appRequests[0]
413
+ };
414
+ }
415
+ async createAppRequest(periodId, login, validateOnly) {
416
+ const messages = [];
417
+ if (!periodId)
418
+ messages.push({ message: 'You must select a period to create an application.', type: 'error', path: 'periodId' });
419
+ if (!login)
420
+ messages.push({ message: 'You must provide a login to create an application.', type: 'error', path: 'login' });
421
+ if (messages.length > 0)
422
+ return { success: false, messages, data: { periodId, login }, id: undefined };
423
+ const response = await this.client.mutation({
424
+ __name: 'CreateAppRequest',
425
+ createAppRequest: {
426
+ __args: { periodId: periodId, login: login, validateOnly },
427
+ success: true,
428
+ messages: {
429
+ message: true,
430
+ type: true,
431
+ arg: true
432
+ },
433
+ appRequest: {
434
+ id: true
150
435
  }
151
436
  }
437
+ });
438
+ return { ...this.mutationForDialog(response.createAppRequest), id: response.createAppRequest.appRequest?.id };
439
+ }
440
+ async appRequestPhaseChange(appRequestId, phaseChange) {
441
+ const response = await this.graphql(`
442
+ mutation AppRequestPhaseChange($appRequestId: ID!) {
443
+ ${phaseChange}(appRequestId: $appRequestId) {
444
+ success
445
+ messages {
446
+ message
447
+ type
448
+ arg
449
+ }
152
450
  }
153
- return { appRequestData: appRequest.data };
451
+ }
452
+ `, { appRequestId });
453
+ return this.mutationForDialog(response[phaseChange]);
154
454
  }
155
- async updatePrompt(promptId, data, validateOnly) {
455
+ async cancelAppRequest(appRequestId, dataVersion) {
156
456
  const response = await this.client.mutation({
157
- __name: 'UpdatePrompt',
158
- updatePrompt: {
159
- __args: { promptId, data, validateOnly },
457
+ __name: 'CancelAppRequest',
458
+ cancelAppRequest: {
459
+ __args: { appRequestId, dataVersion },
160
460
  success: true,
161
461
  messages: {
162
462
  message: true,
@@ -165,13 +465,13 @@ class API extends APIBase {
165
465
  }
166
466
  }
167
467
  });
168
- return this.mutationForDialog(response.updatePrompt);
468
+ return this.mutationForDialog(response.cancelAppRequest);
169
469
  }
170
- async updateConfiguration(periodId, definitionKey, data, validateOnly) {
470
+ async reopenAppRequest(appRequestId) {
171
471
  const response = await this.client.mutation({
172
- __name: 'UpdateConfiguration',
173
- updateConfiguration: {
174
- __args: { periodId, key: definitionKey, data, validateOnly },
472
+ __name: 'ReopenAppRequest',
473
+ reopenAppRequest: {
474
+ __args: { appRequestId },
175
475
  success: true,
176
476
  messages: {
177
477
  message: true,
@@ -180,26 +480,42 @@ class API extends APIBase {
180
480
  }
181
481
  }
182
482
  });
183
- return this.mutationForDialog(response.updateConfiguration);
483
+ return this.mutationForDialog(response.reopenAppRequest);
184
484
  }
185
- async getAppRequestData(appRequestId) {
186
- const response = await this.client.query({
187
- __name: 'GetAppRequestData',
188
- appRequests: {
189
- __args: { filter: { ids: [appRequestId] } },
190
- id: true,
191
- data: true
485
+ async advanceWorkflow(applicationId) {
486
+ const response = await this.client.mutation({
487
+ __name: 'AdvanceWorkflow',
488
+ advanceWorkflow: {
489
+ __args: { applicationId },
490
+ success: true,
491
+ messages: {
492
+ message: true,
493
+ type: true,
494
+ arg: true
495
+ }
192
496
  }
193
497
  });
194
- if (response.appRequests.length === 0)
195
- return {};
196
- const appRequest = response.appRequests[0];
197
- return appRequest.data;
498
+ return this.mutationForDialog(response.advanceWorkflow);
499
+ }
500
+ async reverseWorkflow(applicationId) {
501
+ const response = await this.client.mutation({
502
+ __name: 'ReverseWorkflow',
503
+ reverseWorkflow: {
504
+ __args: { applicationId },
505
+ success: true,
506
+ messages: {
507
+ message: true,
508
+ type: true,
509
+ arg: true
510
+ }
511
+ }
512
+ });
513
+ return this.mutationForDialog(response.reverseWorkflow);
198
514
  }
199
- async submitAppRequest(appRequestId) {
515
+ async closeAppRequest(appRequestId) {
200
516
  const response = await this.client.mutation({
201
- __name: 'SubmitAppRequest',
202
- submitAppRequest: {
517
+ __name: 'CloseAppRequest',
518
+ closeAppRequest: {
203
519
  __args: { appRequestId },
204
520
  success: true,
205
521
  messages: {
@@ -209,14 +525,24 @@ class API extends APIBase {
209
525
  }
210
526
  }
211
527
  });
212
- return this.mutationForDialog(response.submitAppRequest);
528
+ return this.mutationForDialog(response.closeAppRequest);
213
529
  }
214
- async getAppRequests(filter, dest = enumAppRequestIndexDestination.APP_REQUEST_LIST) {
530
+ async getAppRequests(filter, paged, dest = enumAppRequestIndexDestination.APP_REQUEST_LIST) {
531
+ const processedFilter = {
532
+ ...filter,
533
+ indexes: filter?.indexes ? Object.entries(filter.indexes).map(([category, tags]) => ({ category, tags })) : undefined
534
+ };
215
535
  const response = await this.client.query({
216
536
  __name: 'GetAppRequests',
217
537
  appRequests: {
218
- __args: { filter },
538
+ __args: { filter: processedFilter, paged },
219
539
  id: true,
540
+ createdAt: true,
541
+ closedAt: true,
542
+ updatedAt: true,
543
+ applications: {
544
+ title: true
545
+ },
220
546
  applicant: {
221
547
  login: true,
222
548
  fullname: true
@@ -237,13 +563,7 @@ class API extends APIBase {
237
563
  }
238
564
  },
239
565
  actions: {
240
- cancel: true,
241
- close: true,
242
- reopen: true,
243
- return: true,
244
- review: true,
245
- offer: true,
246
- submit: true
566
+ review: true
247
567
  }
248
568
  },
249
569
  appRequestIndexes: {
@@ -257,6 +577,24 @@ class API extends APIBase {
257
577
  value: true,
258
578
  label: true
259
579
  }
580
+ },
581
+ pageInfo: {
582
+ appRequests: {
583
+ currentPage: true,
584
+ totalItems: true,
585
+ hasNextPage: true,
586
+ perPage: true,
587
+ categories: {
588
+ tags: {
589
+ tag: true,
590
+ label: true
591
+ },
592
+ category: true,
593
+ label: true,
594
+ useInFilters: true,
595
+ useInList: true
596
+ }
597
+ }
260
598
  }
261
599
  });
262
600
  return response;
@@ -280,6 +618,9 @@ class API extends APIBase {
280
618
  __name: 'GetBasicRequestData',
281
619
  appRequests: {
282
620
  __args: { filter: { ids: [appRequestId] } },
621
+ complete: true,
622
+ status: true,
623
+ closedAt: true,
283
624
  applicant: {
284
625
  login: true,
285
626
  fullname: true,
@@ -291,7 +632,30 @@ class API extends APIBase {
291
632
  },
292
633
  period: {
293
634
  id: true,
294
- name: true
635
+ name: true,
636
+ code: true,
637
+ openDate: true,
638
+ closeDate: true,
639
+ archiveDate: true
640
+ },
641
+ applications: {
642
+ id: true,
643
+ navTitle: true,
644
+ programKey: true
645
+ },
646
+ actions: {
647
+ acceptOffer: true,
648
+ cancel: true,
649
+ close: true,
650
+ completeRequest: true,
651
+ completeReview: true,
652
+ reopen: true,
653
+ returnToApplicant: true,
654
+ returnToNonBlocking: true,
655
+ returnToOffer: true,
656
+ returnToReview: true,
657
+ review: true,
658
+ submit: true
295
659
  }
296
660
  }
297
661
  });
@@ -299,7 +663,7 @@ class API extends APIBase {
299
663
  return undefined;
300
664
  return response.appRequests[0];
301
665
  }
302
- async getReviewData(appRequestId) {
666
+ async getReviewData(appRequestId, visibilities = [enumPromptVisibility.AVAILABLE, enumPromptVisibility.REQUEST_DUPE]) {
303
667
  const response = await this.client.query({
304
668
  __name: 'GetReviewData',
305
669
  appRequests: {
@@ -309,17 +673,39 @@ class API extends APIBase {
309
673
  data: true,
310
674
  applications: {
311
675
  id: true,
676
+ phase: true,
312
677
  status: true,
313
678
  statusReason: true,
314
679
  title: true,
315
680
  navTitle: true,
681
+ programKey: true,
682
+ workflowStage: {
683
+ key: true,
684
+ blocking: true
685
+ },
686
+ nextWorkflowStage: {
687
+ key: true,
688
+ title: true
689
+ },
690
+ previousWorkflowStage: {
691
+ key: true,
692
+ title: true
693
+ },
694
+ actions: {
695
+ advanceWorkflow: true,
696
+ reverseWorkflow: true
697
+ },
316
698
  requirements: {
317
699
  id: true,
318
700
  type: true,
319
701
  title: true,
320
702
  status: true,
321
703
  statusReason: true,
322
- reachable: true,
704
+ workflowStage: {
705
+ key: true,
706
+ title: true,
707
+ blocking: true
708
+ },
323
709
  prompts: {
324
710
  id: true,
325
711
  key: true,
@@ -327,48 +713,72 @@ class API extends APIBase {
327
713
  navTitle: true,
328
714
  answered: true,
329
715
  visibility: true,
716
+ configurationData: true,
717
+ gatheredConfigData: true,
718
+ moot: true,
719
+ invalidated: true,
720
+ invalidatedReason: true,
721
+ preloadData: true,
722
+ fetchedData: true,
330
723
  actions: {
331
724
  update: true
332
725
  }
333
726
  }
334
727
  }
728
+ },
729
+ actions: {
730
+ acceptOffer: true,
731
+ cancel: true,
732
+ close: true,
733
+ completeRequest: true,
734
+ completeReview: true,
735
+ reopen: true,
736
+ returnToApplicant: true,
737
+ returnToNonBlocking: true,
738
+ returnToOffer: true,
739
+ returnToReview: true,
740
+ review: true,
741
+ submit: true
335
742
  }
336
743
  }
337
744
  });
338
745
  if (response.appRequests.length === 0)
339
746
  return undefined;
340
747
  const appRequest = response.appRequests[0];
341
- return { ...appRequest, applications: appRequest.applications.map(a => ({ ...a, requirements: a.requirements.filter(r => r.reachable).map(r => ({ ...r, prompts: r.prompts.filter(p => p.visibility !== enumPromptVisibility.UNREACHABLE) })) })) };
748
+ return { ...appRequest, applications: appRequest.applications.map(a => ({ ...a, requirements: a.requirements.map(r => ({ ...r, prompts: r.prompts.filter(p => visibilities.includes(p.visibility)) })) })) };
342
749
  }
343
- async getRequestActivity(appRequestId, filters) {
750
+ async getRequestActivity(appRequestId, filters, paged) {
344
751
  const response = await this.client.query({
345
752
  __name: 'GetRequestActivity',
346
- appRequests: {
347
- __args: { filter: { ids: [appRequestId] } },
348
- activity: {
349
- __args: { filters },
350
- id: true,
351
- user: {
352
- login: true,
353
- fullname: true
354
- },
355
- impersonatedBy: {
356
- login: true,
357
- fullname: true
358
- },
359
- action: true,
360
- description: true,
361
- data: true,
362
- createdAt: true
753
+ appRequestActivity: {
754
+ __args: { id: appRequestId, filters, paged },
755
+ id: true,
756
+ user: {
757
+ login: true,
758
+ fullname: true
759
+ },
760
+ impersonatedBy: {
761
+ login: true,
762
+ fullname: true
763
+ },
764
+ action: true,
765
+ description: true,
766
+ data: true,
767
+ createdAt: true
768
+ },
769
+ pageInfo: {
770
+ appRequestsActivity: {
771
+ currentPage: true,
772
+ totalItems: true,
773
+ hasNextPage: true,
774
+ perPage: true
363
775
  }
364
776
  }
365
777
  });
366
- if (response.appRequests.length === 0)
367
- return undefined;
368
- return response.appRequests[0].activity.map(activity => ({
369
- ...activity,
370
- createdAt: DateTime.fromISO(activity.createdAt)
371
- }));
778
+ return {
779
+ activity: response.appRequestActivity,
780
+ pageInfo: response.pageInfo.appRequestsActivity
781
+ };
372
782
  }
373
783
  async getPromptData(appRequestId, promptId) {
374
784
  const response = await this.client.query({
@@ -379,7 +789,8 @@ class API extends APIBase {
379
789
  __args: { promptId },
380
790
  data: true,
381
791
  preloadData: true,
382
- configurationRelatedData: true,
792
+ configurationData: true,
793
+ gatheredConfigData: true,
383
794
  fetchedData: true
384
795
  }
385
796
  }
@@ -393,13 +804,101 @@ class API extends APIBase {
393
804
  periods: {
394
805
  id: true,
395
806
  name: true,
807
+ code: true,
396
808
  openDate: true,
397
809
  closeDate: true,
398
- archiveDate: true
810
+ archiveDate: true,
811
+ reviewed: true,
812
+ actions: {
813
+ update: true,
814
+ delete: true,
815
+ createAppRequest: true
816
+ }
399
817
  }
400
818
  });
401
819
  return response.periods;
402
820
  }
821
+ async getOpenPeriods() {
822
+ const response = await this.client.query({
823
+ __name: 'GetOpenPeriods',
824
+ periods: {
825
+ __args: { filter: { openNow: true } },
826
+ id: true,
827
+ name: true,
828
+ code: true,
829
+ openDate: true,
830
+ closeDate: true,
831
+ archiveDate: true,
832
+ reviewed: true
833
+ }
834
+ });
835
+ return response.periods;
836
+ }
837
+ async createPeriod(period, validateOnly, copyPeriodId) {
838
+ const response = await this.client.mutation({
839
+ __name: 'CreatePeriod',
840
+ createPeriod: {
841
+ __args: { period, validateOnly, copyPeriodId },
842
+ success: true,
843
+ messages: {
844
+ message: true,
845
+ type: true,
846
+ arg: true
847
+ }
848
+ }
849
+ });
850
+ return api.mutationForDialog(response.createPeriod, { prefix: 'period' });
851
+ }
852
+ async updatePeriod(periodId, period, validateOnly) {
853
+ const response = await this.client.mutation({
854
+ __name: 'UpdatePeriod',
855
+ updatePeriod: {
856
+ __args: { periodId, update: period, validateOnly },
857
+ success: true,
858
+ messages: {
859
+ message: true,
860
+ type: true,
861
+ arg: true
862
+ }
863
+ }
864
+ });
865
+ return this.mutationForDialog(response.updatePeriod, { prefix: 'period' });
866
+ }
867
+ async markPeriodReviewed(periodId, validateOnly) {
868
+ const response = await this.client.mutation({
869
+ __name: 'MarkPeriodReviewed',
870
+ markPeriodReviewed: {
871
+ __args: { periodId, validateOnly },
872
+ success: true,
873
+ messages: {
874
+ message: true,
875
+ type: true,
876
+ arg: true
877
+ }
878
+ }
879
+ });
880
+ return this.mutationForDialog(response.markPeriodReviewed, { prefix: 'period' });
881
+ }
882
+ async deletePeriod(periodId) {
883
+ const response = await this.client.mutation({
884
+ __name: 'DeletePeriod',
885
+ deletePeriod: {
886
+ __args: { periodId },
887
+ success: true
888
+ }
889
+ });
890
+ return response.deletePeriod.success;
891
+ }
892
+ async disablePeriodProgramRequirements(periodId, requirementKey, disabled) {
893
+ const response = await this.client.mutation({
894
+ __name: 'updatePeriodProgram',
895
+ updatePeriodRequirement: {
896
+ __args: { periodId, requirementKey, disabled },
897
+ success: true
898
+ }
899
+ });
900
+ return response.updatePeriodRequirement.success;
901
+ }
403
902
  async getPeriodConfigurations(periodId) {
404
903
  const response = await this.client.query({
405
904
  __name: 'GetPeriodConfigurations',
@@ -411,6 +910,7 @@ class API extends APIBase {
411
910
  openDate: true,
412
911
  closeDate: true,
413
912
  archiveDate: true,
913
+ reviewed: true,
414
914
  programs: {
415
915
  key: true,
416
916
  title: true,
@@ -420,6 +920,7 @@ class API extends APIBase {
420
920
  title: true,
421
921
  description: true,
422
922
  enabled: true,
923
+ type: true,
423
924
  configuration: {
424
925
  data: true,
425
926
  actions: {
@@ -446,6 +947,19 @@ class API extends APIBase {
446
947
  const period = response.periods[0];
447
948
  return { programs: period.programs, period };
448
949
  }
950
+ async getConfigurationFetched(periodId, definitionKey) {
951
+ const response = await this.client.query({
952
+ __name: 'GetConfigurationFetched',
953
+ periods: {
954
+ __args: { filter: { ids: [periodId] } },
955
+ configurations: {
956
+ __args: { filter: { keys: [definitionKey] } },
957
+ fetchedData: true
958
+ }
959
+ }
960
+ });
961
+ return response.periods[0].configurations[0]?.fetchedData ?? {};
962
+ }
449
963
  async getRoleList() {
450
964
  const response = await this.client.query({
451
965
  __name: 'GetRoleList',
@@ -453,14 +967,29 @@ class API extends APIBase {
453
967
  id: true,
454
968
  name: true,
455
969
  description: true,
456
- groups: true,
970
+ groups: {
971
+ groupName: true,
972
+ managers: {
973
+ fullname: true,
974
+ email: true
975
+ },
976
+ dateAdded: true,
977
+ dateCreated: true
978
+ },
457
979
  actions: {
458
980
  update: true,
459
981
  delete: true
460
982
  }
461
983
  }
462
984
  });
463
- return response.roles;
985
+ if (response.roles.length === 0)
986
+ return undefined;
987
+ const roles = response.roles;
988
+ return roles.map(role => ({ ...role, groups: role.groups.map((group) => ({
989
+ ...group,
990
+ dateAdded: DateTime.fromISO(group.dateAdded),
991
+ dateCreated: group.dateCreated ? DateTime.fromISO(group.dateCreated) : undefined
992
+ })) }));
464
993
  }
465
994
  async getRoleDetails(roleId) {
466
995
  const response = await this.client.query({
@@ -470,10 +999,18 @@ class API extends APIBase {
470
999
  id: true,
471
1000
  name: true,
472
1001
  description: true,
473
- groups: true,
1002
+ groups: {
1003
+ groupName: true,
1004
+ managers: {
1005
+ fullname: true,
1006
+ email: true
1007
+ },
1008
+ dateAdded: true,
1009
+ dateCreated: true
1010
+ },
474
1011
  grants: {
475
1012
  id: true,
476
- subjectType: {
1013
+ controlGroup: {
477
1014
  name: true,
478
1015
  title: true,
479
1016
  description: true
@@ -500,12 +1037,16 @@ class API extends APIBase {
500
1037
  if (!response.roles.length)
501
1038
  return undefined;
502
1039
  const role = response.roles[0];
503
- return role;
1040
+ return { ...role, groups: role.groups.map((group) => ({
1041
+ ...group,
1042
+ dateAdded: DateTime.fromISO(group.dateAdded),
1043
+ dateCreated: group.dateCreated ? DateTime.fromISO(group.dateCreated) : undefined
1044
+ })) };
504
1045
  }
505
1046
  async getAuthorizationInfo() {
506
1047
  const response = await this.client.query({
507
1048
  __name: 'GetAuthorizationInfo',
508
- subjectTypes: {
1049
+ controlGroups: {
509
1050
  name: true,
510
1051
  title: true,
511
1052
  description: true,
@@ -525,9 +1066,9 @@ class API extends APIBase {
525
1066
  }
526
1067
  }
527
1068
  });
528
- return response.subjectTypes;
1069
+ return response.controlGroups;
529
1070
  }
530
- async upsertRole(roleId, role, validateOnly) {
1071
+ async upsertRole(roleId, role, validateOnly, copyRoleId) {
531
1072
  if (roleId != null) {
532
1073
  const response = await this.client.mutation({
533
1074
  __name: 'UpdateRole',
@@ -547,7 +1088,7 @@ class API extends APIBase {
547
1088
  const response = await this.client.mutation({
548
1089
  __name: 'CreateRole',
549
1090
  roleCreate: {
550
- __args: { role, validateOnly },
1091
+ __args: { role, copyRoleId, validateOnly },
551
1092
  success: true,
552
1093
  messages: {
553
1094
  message: true,