@reqquest/ui 1.0.0 → 1.1.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.
Files changed (47) hide show
  1. package/README.md +8 -0
  2. package/dist/api.js +656 -111
  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 -0
  22. package/dist/status-utils.js +343 -0
  23. package/dist/stores/IStateStore.js +0 -1
  24. package/dist/typed-client/schema.graphql +564 -124
  25. package/dist/typed-client/schema.js +87 -23
  26. package/dist/typed-client/types.js +919 -454
  27. package/dist/util.js +12 -1
  28. package/package.json +39 -40
  29. package/dist/api.d.ts +0 -595
  30. package/dist/components/ButtonLoadingIcon.svelte.d.ts +0 -18
  31. package/dist/components/index.d.ts +0 -1
  32. package/dist/index.d.ts +0 -4
  33. package/dist/registry.d.ts +0 -138
  34. package/dist/stores/IStateStore.d.ts +0 -5
  35. package/dist/typed-client/index.d.ts +0 -25
  36. package/dist/typed-client/runtime/batcher.d.ts +0 -105
  37. package/dist/typed-client/runtime/createClient.d.ts +0 -17
  38. package/dist/typed-client/runtime/error.d.ts +0 -18
  39. package/dist/typed-client/runtime/fetcher.d.ts +0 -10
  40. package/dist/typed-client/runtime/generateGraphqlOperation.d.ts +0 -30
  41. package/dist/typed-client/runtime/index.d.ts +0 -11
  42. package/dist/typed-client/runtime/linkTypeMap.d.ts +0 -9
  43. package/dist/typed-client/runtime/typeSelection.d.ts +0 -28
  44. package/dist/typed-client/runtime/types.d.ts +0 -55
  45. package/dist/typed-client/schema.d.ts +0 -1483
  46. package/dist/typed-client/types.d.ts +0 -540
  47. 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,439 @@ 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 {};
174
+ }
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);
74
189
  }
75
- async getApplyNavigation(appRequestId) {
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
  }
139
397
  }
140
398
  }
141
399
  });
142
400
  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 };
401
+ throw error(404, 'Application request not found');
402
+ const splitInfo = API.splitPromptsForApplicant(response.appRequests[0]?.applications ?? []);
403
+ return {
404
+ ...omit(splitInfo, 'applicationsForNavNoDupes', 'applicationsForNavWithDupes', 'applicationsReviewNoDupes', 'applicationsReviewWithDupes'),
405
+ applicationsForNav: showDupePrompts ? splitInfo.applicationsForNavWithDupes : splitInfo.applicationsForNavNoDupes,
406
+ applicationsReview: showDupePrompts ? splitInfo.applicationsReviewWithDupes : splitInfo.applicationsReviewNoDupes,
407
+ applicationsAccept: showDupePrompts ? splitInfo.applicationsAcceptWithDupes : splitInfo.applicationsAcceptNoDupes,
408
+ appRequest: response.appRequests[0]
409
+ };
410
+ }
411
+ async createAppRequest(periodId, login, validateOnly) {
412
+ const messages = [];
413
+ if (!periodId)
414
+ messages.push({ message: 'You must select a period to create an application.', type: 'error', path: 'periodId' });
415
+ if (!login)
416
+ messages.push({ message: 'You must provide a login to create an application.', type: 'error', path: 'login' });
417
+ if (messages.length > 0)
418
+ return { success: false, messages, data: { periodId, login }, id: undefined };
419
+ const response = await this.client.mutation({
420
+ __name: 'CreateAppRequest',
421
+ createAppRequest: {
422
+ __args: { periodId: periodId, login: login, validateOnly },
423
+ success: true,
424
+ messages: {
425
+ message: true,
426
+ type: true,
427
+ arg: true
428
+ },
429
+ appRequest: {
430
+ id: true
150
431
  }
151
432
  }
433
+ });
434
+ return { ...this.mutationForDialog(response.createAppRequest), id: response.createAppRequest.appRequest?.id };
435
+ }
436
+ async appRequestPhaseChange(appRequestId, phaseChange) {
437
+ const response = await this.graphql(`
438
+ mutation AppRequestPhaseChange($appRequestId: ID!) {
439
+ ${phaseChange}(appRequestId: $appRequestId) {
440
+ success
441
+ messages {
442
+ message
443
+ type
444
+ arg
445
+ }
152
446
  }
153
- return { appRequestData: appRequest.data };
447
+ }
448
+ `, { appRequestId });
449
+ return this.mutationForDialog(response[phaseChange]);
154
450
  }
155
- async updatePrompt(promptId, data, validateOnly) {
451
+ async cancelAppRequest(appRequestId, dataVersion) {
156
452
  const response = await this.client.mutation({
157
- __name: 'UpdatePrompt',
158
- updatePrompt: {
159
- __args: { promptId, data, validateOnly },
453
+ __name: 'CancelAppRequest',
454
+ cancelAppRequest: {
455
+ __args: { appRequestId, dataVersion },
160
456
  success: true,
161
457
  messages: {
162
458
  message: true,
@@ -165,13 +461,13 @@ class API extends APIBase {
165
461
  }
166
462
  }
167
463
  });
168
- return this.mutationForDialog(response.updatePrompt);
464
+ return this.mutationForDialog(response.cancelAppRequest);
169
465
  }
170
- async updateConfiguration(periodId, definitionKey, data, validateOnly) {
466
+ async reopenAppRequest(appRequestId) {
171
467
  const response = await this.client.mutation({
172
- __name: 'UpdateConfiguration',
173
- updateConfiguration: {
174
- __args: { periodId, key: definitionKey, data, validateOnly },
468
+ __name: 'ReopenAppRequest',
469
+ reopenAppRequest: {
470
+ __args: { appRequestId },
175
471
  success: true,
176
472
  messages: {
177
473
  message: true,
@@ -180,26 +476,42 @@ class API extends APIBase {
180
476
  }
181
477
  }
182
478
  });
183
- return this.mutationForDialog(response.updateConfiguration);
479
+ return this.mutationForDialog(response.reopenAppRequest);
184
480
  }
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
481
+ async advanceWorkflow(applicationId) {
482
+ const response = await this.client.mutation({
483
+ __name: 'AdvanceWorkflow',
484
+ advanceWorkflow: {
485
+ __args: { applicationId },
486
+ success: true,
487
+ messages: {
488
+ message: true,
489
+ type: true,
490
+ arg: true
491
+ }
192
492
  }
193
493
  });
194
- if (response.appRequests.length === 0)
195
- return {};
196
- const appRequest = response.appRequests[0];
197
- return appRequest.data;
494
+ return this.mutationForDialog(response.advanceWorkflow);
198
495
  }
199
- async submitAppRequest(appRequestId) {
496
+ async reverseWorkflow(applicationId) {
200
497
  const response = await this.client.mutation({
201
- __name: 'SubmitAppRequest',
202
- submitAppRequest: {
498
+ __name: 'ReverseWorkflow',
499
+ reverseWorkflow: {
500
+ __args: { applicationId },
501
+ success: true,
502
+ messages: {
503
+ message: true,
504
+ type: true,
505
+ arg: true
506
+ }
507
+ }
508
+ });
509
+ return this.mutationForDialog(response.reverseWorkflow);
510
+ }
511
+ async closeAppRequest(appRequestId) {
512
+ const response = await this.client.mutation({
513
+ __name: 'CloseAppRequest',
514
+ closeAppRequest: {
203
515
  __args: { appRequestId },
204
516
  success: true,
205
517
  messages: {
@@ -209,14 +521,24 @@ class API extends APIBase {
209
521
  }
210
522
  }
211
523
  });
212
- return this.mutationForDialog(response.submitAppRequest);
524
+ return this.mutationForDialog(response.closeAppRequest);
213
525
  }
214
- async getAppRequests(filter, dest = enumAppRequestIndexDestination.APP_REQUEST_LIST) {
526
+ async getAppRequests(filter, paged, dest = enumAppRequestIndexDestination.APP_REQUEST_LIST) {
527
+ const processedFilter = {
528
+ ...filter,
529
+ indexes: filter?.indexes ? Object.entries(filter.indexes).map(([category, tags]) => ({ category, tags })) : undefined
530
+ };
215
531
  const response = await this.client.query({
216
532
  __name: 'GetAppRequests',
217
533
  appRequests: {
218
- __args: { filter },
534
+ __args: { filter: processedFilter, paged },
219
535
  id: true,
536
+ createdAt: true,
537
+ closedAt: true,
538
+ updatedAt: true,
539
+ applications: {
540
+ title: true
541
+ },
220
542
  applicant: {
221
543
  login: true,
222
544
  fullname: true
@@ -237,13 +559,7 @@ class API extends APIBase {
237
559
  }
238
560
  },
239
561
  actions: {
240
- cancel: true,
241
- close: true,
242
- reopen: true,
243
- return: true,
244
- review: true,
245
- offer: true,
246
- submit: true
562
+ review: true
247
563
  }
248
564
  },
249
565
  appRequestIndexes: {
@@ -257,6 +573,24 @@ class API extends APIBase {
257
573
  value: true,
258
574
  label: true
259
575
  }
576
+ },
577
+ pageInfo: {
578
+ appRequests: {
579
+ currentPage: true,
580
+ totalItems: true,
581
+ hasNextPage: true,
582
+ perPage: true,
583
+ categories: {
584
+ tags: {
585
+ tag: true,
586
+ label: true
587
+ },
588
+ category: true,
589
+ label: true,
590
+ useInFilters: true,
591
+ useInList: true
592
+ }
593
+ }
260
594
  }
261
595
  });
262
596
  return response;
@@ -280,6 +614,9 @@ class API extends APIBase {
280
614
  __name: 'GetBasicRequestData',
281
615
  appRequests: {
282
616
  __args: { filter: { ids: [appRequestId] } },
617
+ complete: true,
618
+ status: true,
619
+ closedAt: true,
283
620
  applicant: {
284
621
  login: true,
285
622
  fullname: true,
@@ -291,7 +628,30 @@ class API extends APIBase {
291
628
  },
292
629
  period: {
293
630
  id: true,
294
- name: true
631
+ name: true,
632
+ code: true,
633
+ openDate: true,
634
+ closeDate: true,
635
+ archiveDate: true
636
+ },
637
+ applications: {
638
+ id: true,
639
+ navTitle: true,
640
+ programKey: true
641
+ },
642
+ actions: {
643
+ acceptOffer: true,
644
+ cancel: true,
645
+ close: true,
646
+ completeRequest: true,
647
+ completeReview: true,
648
+ reopen: true,
649
+ returnToApplicant: true,
650
+ returnToNonBlocking: true,
651
+ returnToOffer: true,
652
+ returnToReview: true,
653
+ review: true,
654
+ submit: true
295
655
  }
296
656
  }
297
657
  });
@@ -299,7 +659,7 @@ class API extends APIBase {
299
659
  return undefined;
300
660
  return response.appRequests[0];
301
661
  }
302
- async getReviewData(appRequestId) {
662
+ async getReviewData(appRequestId, visibilities = [enumPromptVisibility.AVAILABLE, enumPromptVisibility.REQUEST_DUPE]) {
303
663
  const response = await this.client.query({
304
664
  __name: 'GetReviewData',
305
665
  appRequests: {
@@ -309,17 +669,39 @@ class API extends APIBase {
309
669
  data: true,
310
670
  applications: {
311
671
  id: true,
672
+ phase: true,
312
673
  status: true,
313
674
  statusReason: true,
314
675
  title: true,
315
676
  navTitle: true,
677
+ programKey: true,
678
+ workflowStage: {
679
+ key: true,
680
+ blocking: true
681
+ },
682
+ nextWorkflowStage: {
683
+ key: true,
684
+ title: true
685
+ },
686
+ previousWorkflowStage: {
687
+ key: true,
688
+ title: true
689
+ },
690
+ actions: {
691
+ advanceWorkflow: true,
692
+ reverseWorkflow: true
693
+ },
316
694
  requirements: {
317
695
  id: true,
318
696
  type: true,
319
697
  title: true,
320
698
  status: true,
321
699
  statusReason: true,
322
- reachable: true,
700
+ workflowStage: {
701
+ key: true,
702
+ title: true,
703
+ blocking: true
704
+ },
323
705
  prompts: {
324
706
  id: true,
325
707
  key: true,
@@ -327,26 +709,47 @@ class API extends APIBase {
327
709
  navTitle: true,
328
710
  answered: true,
329
711
  visibility: true,
712
+ configurationData: true,
713
+ gatheredConfigData: true,
714
+ moot: true,
715
+ invalidated: true,
716
+ invalidatedReason: true,
717
+ preloadData: true,
718
+ fetchedData: true,
330
719
  actions: {
331
720
  update: true
332
721
  }
333
722
  }
334
723
  }
724
+ },
725
+ actions: {
726
+ acceptOffer: true,
727
+ cancel: true,
728
+ close: true,
729
+ completeRequest: true,
730
+ completeReview: true,
731
+ reopen: true,
732
+ returnToApplicant: true,
733
+ returnToNonBlocking: true,
734
+ returnToOffer: true,
735
+ returnToReview: true,
736
+ review: true,
737
+ submit: true
335
738
  }
336
739
  }
337
740
  });
338
741
  if (response.appRequests.length === 0)
339
742
  return undefined;
340
743
  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) })) })) };
744
+ return { ...appRequest, applications: appRequest.applications.map(a => ({ ...a, requirements: a.requirements.map(r => ({ ...r, prompts: r.prompts.filter(p => visibilities.includes(p.visibility)) })) })) };
342
745
  }
343
- async getRequestActivity(appRequestId, filters) {
746
+ async getRequestActivity(appRequestId, filters, paged) {
344
747
  const response = await this.client.query({
345
748
  __name: 'GetRequestActivity',
346
749
  appRequests: {
347
750
  __args: { filter: { ids: [appRequestId] } },
348
751
  activity: {
349
- __args: { filters },
752
+ __args: { filters, paged },
350
753
  id: true,
351
754
  user: {
352
755
  login: true,
@@ -361,14 +764,25 @@ class API extends APIBase {
361
764
  data: true,
362
765
  createdAt: true
363
766
  }
767
+ },
768
+ pageInfo: {
769
+ appRequestsActivity: {
770
+ currentPage: true,
771
+ totalItems: true,
772
+ hasNextPage: true,
773
+ perPage: true
774
+ }
364
775
  }
365
776
  });
366
777
  if (response.appRequests.length === 0)
367
778
  return undefined;
368
- return response.appRequests[0].activity.map(activity => ({
369
- ...activity,
370
- createdAt: DateTime.fromISO(activity.createdAt)
371
- }));
779
+ return {
780
+ activity: response.appRequests[0].activity.map(activity => ({
781
+ ...activity,
782
+ createdAt: DateTime.fromISO(activity.createdAt)
783
+ })),
784
+ pageInfo: response.pageInfo.appRequestsActivity
785
+ };
372
786
  }
373
787
  async getPromptData(appRequestId, promptId) {
374
788
  const response = await this.client.query({
@@ -379,7 +793,8 @@ class API extends APIBase {
379
793
  __args: { promptId },
380
794
  data: true,
381
795
  preloadData: true,
382
- configurationRelatedData: true,
796
+ configurationData: true,
797
+ gatheredConfigData: true,
383
798
  fetchedData: true
384
799
  }
385
800
  }
@@ -393,13 +808,101 @@ class API extends APIBase {
393
808
  periods: {
394
809
  id: true,
395
810
  name: true,
811
+ code: true,
396
812
  openDate: true,
397
813
  closeDate: true,
398
- archiveDate: true
814
+ archiveDate: true,
815
+ reviewed: true,
816
+ actions: {
817
+ update: true,
818
+ delete: true,
819
+ createAppRequest: true
820
+ }
399
821
  }
400
822
  });
401
823
  return response.periods;
402
824
  }
825
+ async getOpenPeriods() {
826
+ const response = await this.client.query({
827
+ __name: 'GetOpenPeriods',
828
+ periods: {
829
+ __args: { filter: { openNow: true } },
830
+ id: true,
831
+ name: true,
832
+ code: true,
833
+ openDate: true,
834
+ closeDate: true,
835
+ archiveDate: true,
836
+ reviewed: true
837
+ }
838
+ });
839
+ return response.periods;
840
+ }
841
+ async createPeriod(period, validateOnly, copyPeriodId) {
842
+ const response = await this.client.mutation({
843
+ __name: 'CreatePeriod',
844
+ createPeriod: {
845
+ __args: { period, validateOnly, copyPeriodId },
846
+ success: true,
847
+ messages: {
848
+ message: true,
849
+ type: true,
850
+ arg: true
851
+ }
852
+ }
853
+ });
854
+ return api.mutationForDialog(response.createPeriod, { prefix: 'period' });
855
+ }
856
+ async updatePeriod(periodId, period, validateOnly) {
857
+ const response = await this.client.mutation({
858
+ __name: 'UpdatePeriod',
859
+ updatePeriod: {
860
+ __args: { periodId, update: period, validateOnly },
861
+ success: true,
862
+ messages: {
863
+ message: true,
864
+ type: true,
865
+ arg: true
866
+ }
867
+ }
868
+ });
869
+ return this.mutationForDialog(response.updatePeriod, { prefix: 'period' });
870
+ }
871
+ async markPeriodReviewed(periodId, validateOnly) {
872
+ const response = await this.client.mutation({
873
+ __name: 'MarkPeriodReviewed',
874
+ markPeriodReviewed: {
875
+ __args: { periodId, validateOnly },
876
+ success: true,
877
+ messages: {
878
+ message: true,
879
+ type: true,
880
+ arg: true
881
+ }
882
+ }
883
+ });
884
+ return this.mutationForDialog(response.markPeriodReviewed, { prefix: 'period' });
885
+ }
886
+ async deletePeriod(periodId) {
887
+ const response = await this.client.mutation({
888
+ __name: 'DeletePeriod',
889
+ deletePeriod: {
890
+ __args: { periodId },
891
+ success: true
892
+ }
893
+ });
894
+ return response.deletePeriod.success;
895
+ }
896
+ async disablePeriodProgramRequirements(periodId, requirementKey, disabled) {
897
+ const response = await this.client.mutation({
898
+ __name: 'updatePeriodProgram',
899
+ updatePeriodRequirement: {
900
+ __args: { periodId, requirementKey, disabled },
901
+ success: true
902
+ }
903
+ });
904
+ return response.updatePeriodRequirement.success;
905
+ }
403
906
  async getPeriodConfigurations(periodId) {
404
907
  const response = await this.client.query({
405
908
  __name: 'GetPeriodConfigurations',
@@ -411,6 +914,7 @@ class API extends APIBase {
411
914
  openDate: true,
412
915
  closeDate: true,
413
916
  archiveDate: true,
917
+ reviewed: true,
414
918
  programs: {
415
919
  key: true,
416
920
  title: true,
@@ -420,6 +924,7 @@ class API extends APIBase {
420
924
  title: true,
421
925
  description: true,
422
926
  enabled: true,
927
+ type: true,
423
928
  configuration: {
424
929
  data: true,
425
930
  actions: {
@@ -446,6 +951,19 @@ class API extends APIBase {
446
951
  const period = response.periods[0];
447
952
  return { programs: period.programs, period };
448
953
  }
954
+ async getConfigurationFetched(periodId, definitionKey) {
955
+ const response = await this.client.query({
956
+ __name: 'GetConfigurationFetched',
957
+ periods: {
958
+ __args: { filter: { ids: [periodId] } },
959
+ configurations: {
960
+ __args: { filter: { keys: [definitionKey] } },
961
+ fetchedData: true
962
+ }
963
+ }
964
+ });
965
+ return response.periods[0].configurations[0]?.fetchedData ?? {};
966
+ }
449
967
  async getRoleList() {
450
968
  const response = await this.client.query({
451
969
  __name: 'GetRoleList',
@@ -453,14 +971,29 @@ class API extends APIBase {
453
971
  id: true,
454
972
  name: true,
455
973
  description: true,
456
- groups: true,
974
+ groups: {
975
+ groupName: true,
976
+ managers: {
977
+ fullname: true,
978
+ email: true
979
+ },
980
+ dateAdded: true,
981
+ dateCreated: true
982
+ },
457
983
  actions: {
458
984
  update: true,
459
985
  delete: true
460
986
  }
461
987
  }
462
988
  });
463
- return response.roles;
989
+ if (response.roles.length === 0)
990
+ return undefined;
991
+ const roles = response.roles;
992
+ return roles.map(role => ({ ...role, groups: role.groups.map((group) => ({
993
+ ...group,
994
+ dateAdded: DateTime.fromISO(group.dateAdded),
995
+ dateCreated: group.dateCreated ? DateTime.fromISO(group.dateCreated) : undefined
996
+ })) }));
464
997
  }
465
998
  async getRoleDetails(roleId) {
466
999
  const response = await this.client.query({
@@ -470,10 +1003,18 @@ class API extends APIBase {
470
1003
  id: true,
471
1004
  name: true,
472
1005
  description: true,
473
- groups: true,
1006
+ groups: {
1007
+ groupName: true,
1008
+ managers: {
1009
+ fullname: true,
1010
+ email: true
1011
+ },
1012
+ dateAdded: true,
1013
+ dateCreated: true
1014
+ },
474
1015
  grants: {
475
1016
  id: true,
476
- subjectType: {
1017
+ controlGroup: {
477
1018
  name: true,
478
1019
  title: true,
479
1020
  description: true
@@ -500,12 +1041,16 @@ class API extends APIBase {
500
1041
  if (!response.roles.length)
501
1042
  return undefined;
502
1043
  const role = response.roles[0];
503
- return role;
1044
+ return { ...role, groups: role.groups.map((group) => ({
1045
+ ...group,
1046
+ dateAdded: DateTime.fromISO(group.dateAdded),
1047
+ dateCreated: group.dateCreated ? DateTime.fromISO(group.dateCreated) : undefined
1048
+ })) };
504
1049
  }
505
1050
  async getAuthorizationInfo() {
506
1051
  const response = await this.client.query({
507
1052
  __name: 'GetAuthorizationInfo',
508
- subjectTypes: {
1053
+ controlGroups: {
509
1054
  name: true,
510
1055
  title: true,
511
1056
  description: true,
@@ -525,9 +1070,9 @@ class API extends APIBase {
525
1070
  }
526
1071
  }
527
1072
  });
528
- return response.subjectTypes;
1073
+ return response.controlGroups;
529
1074
  }
530
- async upsertRole(roleId, role, validateOnly) {
1075
+ async upsertRole(roleId, role, validateOnly, copyRoleId) {
531
1076
  if (roleId != null) {
532
1077
  const response = await this.client.mutation({
533
1078
  __name: 'UpdateRole',
@@ -547,7 +1092,7 @@ class API extends APIBase {
547
1092
  const response = await this.client.mutation({
548
1093
  __name: 'CreateRole',
549
1094
  roleCreate: {
550
- __args: { role, validateOnly },
1095
+ __args: { role, copyRoleId, validateOnly },
551
1096
  success: true,
552
1097
  messages: {
553
1098
  message: true,