browsergym-workarena 0.2.1__py3-none-any.whl → 0.3.1__py3-none-any.whl

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 (91) hide show
  1. browsergym/workarena/__init__.py +13 -1
  2. browsergym/workarena/api/category.py +74 -0
  3. browsergym/workarena/api/change_request.py +87 -0
  4. browsergym/workarena/api/computer_asset.py +90 -0
  5. browsergym/workarena/api/cost_center.py +19 -0
  6. browsergym/workarena/api/expense_line.py +89 -0
  7. browsergym/workarena/api/incident.py +45 -0
  8. browsergym/workarena/api/knowledge.py +29 -0
  9. browsergym/workarena/api/problem.py +90 -0
  10. browsergym/workarena/api/report.py +183 -0
  11. browsergym/workarena/api/requested_items.py +63 -0
  12. browsergym/workarena/api/user.py +11 -8
  13. browsergym/workarena/api/utils.py +47 -3
  14. browsergym/workarena/config.py +21 -1
  15. browsergym/workarena/data_files/setup_files/forms/expected_incident_form_fields.json +1 -1
  16. browsergym/workarena/data_files/setup_files/forms/expected_request_item_form_fields.json +1 -0
  17. browsergym/workarena/data_files/setup_files/knowledge/protocols.json +46 -0
  18. browsergym/workarena/data_files/setup_files/knowledge/test.html +1 -0
  19. browsergym/workarena/data_files/setup_files/lists/expected_asset_list_columns.json +2 -24
  20. browsergym/workarena/data_files/setup_files/lists/expected_change_request_list_columns.json +4 -40
  21. browsergym/workarena/data_files/setup_files/lists/expected_expense_line_list_columns.json +12 -0
  22. browsergym/workarena/data_files/setup_files/lists/expected_hardware_list_columns.json +1 -42
  23. browsergym/workarena/data_files/setup_files/lists/expected_incident_list_columns.json +2 -18
  24. browsergym/workarena/data_files/setup_files/lists/expected_problem_list_columns.json +12 -0
  25. browsergym/workarena/data_files/setup_files/lists/expected_requested_items_list_columns.json +12 -0
  26. browsergym/workarena/data_files/setup_files/lists/expected_service_catalog_list_columns.json +2 -19
  27. browsergym/workarena/data_files/setup_files/lists/expected_user_list_columns.json +3 -50
  28. browsergym/workarena/data_files/task_configs/all_menu.json +1 -1
  29. browsergym/workarena/data_files/task_configs/dashboard_retrieval_minmax_task.json +1 -1
  30. browsergym/workarena/data_files/task_configs/dashboard_retrieval_value_task.json +1 -1
  31. browsergym/workarena/data_files/task_configs/filter_service_catalog_item_list_task.json +1 -1
  32. browsergym/workarena/data_files/task_configs/impersonation_users.json +1 -1
  33. browsergym/workarena/data_files/task_configs/report_retrieval_minmax_task.json +1 -1
  34. browsergym/workarena/data_files/task_configs/report_retrieval_value_task.json +1 -1
  35. browsergym/workarena/human_eval/console.js +176 -0
  36. browsergym/workarena/human_eval/tool.py +366 -0
  37. browsergym/workarena/install.py +81 -20
  38. browsergym/workarena/tasks/base.py +55 -20
  39. browsergym/workarena/tasks/comp_building_block.py +4 -0
  40. browsergym/workarena/tasks/compositional/__init__.py +76 -0
  41. browsergym/workarena/tasks/compositional/base.py +364 -0
  42. browsergym/workarena/tasks/compositional/dash_do_base.py +1366 -0
  43. browsergym/workarena/tasks/compositional/dash_do_catalog.py +1127 -0
  44. browsergym/workarena/tasks/compositional/dash_do_catalog_infeasible.py +2047 -0
  45. browsergym/workarena/tasks/compositional/dash_do_create_incident.py +403 -0
  46. browsergym/workarena/tasks/compositional/dash_do_create_incident_infeasible.py +278 -0
  47. browsergym/workarena/tasks/compositional/dash_do_create_problem.py +336 -0
  48. browsergym/workarena/tasks/compositional/dash_do_create_problem_infeasible.py +235 -0
  49. browsergym/workarena/tasks/compositional/dash_do_filter.py +1600 -0
  50. browsergym/workarena/tasks/compositional/dash_do_request_item.py +1315 -0
  51. browsergym/workarena/tasks/compositional/dash_do_request_item_infeasible.py +693 -0
  52. browsergym/workarena/tasks/compositional/delete_record.py +341 -0
  53. browsergym/workarena/tasks/compositional/edit_knowledge_base.py +457 -0
  54. browsergym/workarena/tasks/compositional/expense_management.py +598 -0
  55. browsergym/workarena/tasks/compositional/filter_and_do.py +139 -0
  56. browsergym/workarena/tasks/compositional/find_and_order_item.py +345 -0
  57. browsergym/workarena/tasks/compositional/manage_change_request_schedule.py +1417 -0
  58. browsergym/workarena/tasks/compositional/mark_duplicate_problems.py +499 -0
  59. browsergym/workarena/tasks/compositional/maximize_investment_return.py +1763 -0
  60. browsergym/workarena/tasks/compositional/navigate_and_do.py +1151 -0
  61. browsergym/workarena/tasks/compositional/navigate_and_do_infeasible.py +2100 -0
  62. browsergym/workarena/tasks/compositional/offboard_user.py +207 -0
  63. browsergym/workarena/tasks/compositional/onboard_user.py +226 -0
  64. browsergym/workarena/tasks/compositional/update_task.py +145 -0
  65. browsergym/workarena/tasks/compositional/utils/curriculum.py +215 -0
  66. browsergym/workarena/tasks/compositional/utils/infeasible_configs.py +151 -0
  67. browsergym/workarena/tasks/compositional/utils/knapsack.py +192 -0
  68. browsergym/workarena/tasks/compositional/warranty_check.py +227 -0
  69. browsergym/workarena/tasks/compositional/work_assignment.py +804 -0
  70. browsergym/workarena/tasks/compositional/workload_balancing.py +396 -0
  71. browsergym/workarena/tasks/dashboard.py +194 -12
  72. browsergym/workarena/tasks/form.py +1024 -232
  73. browsergym/workarena/tasks/knowledge.py +216 -25
  74. browsergym/workarena/tasks/list.py +519 -102
  75. browsergym/workarena/tasks/mark_duplicate_problem.py +171 -0
  76. browsergym/workarena/tasks/navigation.py +55 -13
  77. browsergym/workarena/tasks/scripts/extract_all_menu_items.py +9 -2
  78. browsergym/workarena/tasks/scripts/generate_dashboard_configs.py +6 -5
  79. browsergym/workarena/tasks/scripts/service_catalog.py +2 -1
  80. browsergym/workarena/tasks/scripts/validate.py +8 -2
  81. browsergym/workarena/tasks/send_chat_message.py +90 -0
  82. browsergym/workarena/tasks/service_catalog.py +94 -26
  83. browsergym/workarena/tasks/utils/form.py +1 -4
  84. browsergym/workarena/tasks/utils/private_tasks.py +63 -0
  85. browsergym/workarena/tasks/utils/utils.py +13 -0
  86. {browsergym_workarena-0.2.1.dist-info → browsergym_workarena-0.3.1.dist-info}/METADATA +19 -18
  87. browsergym_workarena-0.3.1.dist-info/RECORD +138 -0
  88. {browsergym_workarena-0.2.1.dist-info → browsergym_workarena-0.3.1.dist-info}/entry_points.txt +1 -0
  89. browsergym_workarena-0.2.1.dist-info/RECORD +0 -85
  90. {browsergym_workarena-0.2.1.dist-info → browsergym_workarena-0.3.1.dist-info}/WHEEL +0 -0
  91. {browsergym_workarena-0.2.1.dist-info → browsergym_workarena-0.3.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,183 @@
1
+ import numpy as np
2
+
3
+ from ..instance import SNowInstance
4
+ from .utils import table_api_call
5
+
6
+
7
+ def create_report(
8
+ instance: SNowInstance,
9
+ table: str,
10
+ filter_hashtag: str,
11
+ field: str,
12
+ plot_title: str,
13
+ filter_field: str = "short_description",
14
+ random: np.random = None,
15
+ ) -> list[str]:
16
+ """
17
+ Create a report for for the given table using a filter (str added to the short description).
18
+ The report is created with a random color palette and colors and a random plot type (pie or bar).
19
+
20
+ Parameters:
21
+ -----------
22
+ instance: SNowInstance
23
+ The instance to create the category in
24
+ table: str
25
+ The name of the table used to make the plot
26
+ field: str
27
+ The field of the table used to make the plot
28
+ filter_hashtag: str
29
+ The name of the hashtag to filter the table with
30
+ plot_title: str
31
+ The title of the plot
32
+
33
+ Returns:
34
+ --------
35
+ sys_id: str; sys_id of the report created
36
+ plot_title: str; The title of the plot
37
+
38
+ """
39
+ # select a random color palette for the plot
40
+ color_palettes = table_api_call(
41
+ instance=instance,
42
+ table="pa_chart_color_schemes",
43
+ params={
44
+ "sysparm_fields": "sys_id",
45
+ },
46
+ method="GET",
47
+ )["result"]
48
+
49
+ color_palette_sys_id = random.choice(color_palettes)["sys_id"]
50
+
51
+ # Get available colors to eventually randomly select from them
52
+ colors = table_api_call(
53
+ instance=instance,
54
+ table="sys_report_color",
55
+ params={
56
+ "sysparm_fields": "sys_id",
57
+ },
58
+ method="GET",
59
+ )["result"]
60
+
61
+ # Select a random plot type
62
+ plot_types = ["pie", "bar"]
63
+ plot_type = random.choice(plot_types)
64
+
65
+ report_params = {
66
+ "show_data_label_position_middle": False,
67
+ "display_row_lines": False,
68
+ "is_published": False,
69
+ "chart_title_y_position": "0",
70
+ "gauge_autoscale": True,
71
+ "type": f"{plot_type}",
72
+ "formatting_configuration": {
73
+ "table": "incident",
74
+ "stringFormattingProperties": {},
75
+ "durationFormattingProperties": {},
76
+ "dateFormattingProperties": {},
77
+ "numberFormattingProperties": {},
78
+ },
79
+ "apply_alias": False,
80
+ "chart_border_color": f"{random.choice(colors)['sys_id']}", # default: "65b30218a9fe3dba0120df8611520d97"
81
+ "custom_chart_title_position": False,
82
+ "other_threshold": "-2",
83
+ "y_axis_title_color": f"{random.choice(colors)['sys_id']}", # default: "65b30218a9fe3dba0120df8611520d97"
84
+ "show_legend_border": False,
85
+ "donut_width_percent": "30",
86
+ "y_axis_title_size": "12",
87
+ "legend_border_color": f"{random.choice(colors)['sys_id']}", # default: "65b30218a9fe3dba0120df8611520d97"
88
+ "y_axis_label_bold": False,
89
+ "chart_title_size": "16",
90
+ "x_axis_label_color": f"{random.choice(colors)['sys_id']}", # default: "65b30218a9fe3dba0120df8611520d97"
91
+ "active": True,
92
+ "source_type": "table",
93
+ "x_axis_title_bold": True,
94
+ "x_axis_opposite": False,
95
+ "chart_height": "450",
96
+ "legend_border_radius": "0",
97
+ "field": field,
98
+ "show_geographical_label": False,
99
+ "legend_horizontal_alignment": "center",
100
+ "interval": "year",
101
+ "show_zero": False,
102
+ "y_axis_grid_width": "1",
103
+ "chart_subtitle_size": "14",
104
+ "x_axis_display_grid": False,
105
+ "show_chart_total": False,
106
+ "chart_subtitle_style": "normal",
107
+ "chart_title_style": "normal",
108
+ "x_axis_grid_width": "1",
109
+ "x_axis_label_tilt": "0",
110
+ "show_chart_title": "report",
111
+ "title_vertical_alignment": "top",
112
+ "legend_border_width": "1",
113
+ "compute_percent": "aggregate",
114
+ "show_marker": False,
115
+ "sys_scope": "global",
116
+ "map": "93b8a3a2d7101200bd4a4ebfae61033a",
117
+ "use_color_heatmap": False,
118
+ "use_null_in_trend": False,
119
+ "y_axis_label_tilt": "0",
120
+ "table": table,
121
+ "legend_vertical_alignment": "bottom",
122
+ "x_axis_label_bold": False,
123
+ "no_bulk_migration": False,
124
+ "filter": f"{filter_field}LIKE{filter_hashtag}",
125
+ "display_column_lines": False,
126
+ "x_axis_allow_decimals": True,
127
+ "custom_chart_size": False,
128
+ "title_horizontal_alignment": "center",
129
+ "bar_unstack": False,
130
+ "y_axis_allow_decimals": True,
131
+ "chart_width": "600",
132
+ "x_axis_title_size": "12",
133
+ "y_axis_opposite": False,
134
+ "y_axis_title_bold": True,
135
+ "decimal_precision": "2",
136
+ "y_axis_label_size": "11",
137
+ "x_axis_grid_color": f"{random.choice(colors)['sys_id']}",
138
+ "legend_align_columns": True,
139
+ "field_list": "active,short_description,incident_state,business_duration,calendar_duration,description,caller_id,location,closed_by,impact,cmdb_ci,priority,assigned_to,activity_due,task_effective_number,company,escalation,sys_created_on,closed_at,child_incidents,state,assignment_group,category,number,business_stc",
140
+ "is_scheduled": False,
141
+ "others": True,
142
+ "x_axis_title_color": f"{random.choice(colors)['sys_id']}", # default: "65b30218a9fe3dba0120df8611520d97"
143
+ "aggregation_source": "no_override",
144
+ "chart_title_color": f"{random.choice(colors)['sys_id']}", # default: "65b30218a9fe3dba0120df8611520d97"
145
+ "y_axis_grid_dotted": False,
146
+ "chart_size": "large",
147
+ "legend_items_left_align": False,
148
+ "show_chart_data_label": False,
149
+ "y_axis_grid_color": f"{random.choice(colors)['sys_id']}",
150
+ "allow_data_label_overlap": False,
151
+ "chart_border_radius": "0",
152
+ "title": plot_title,
153
+ "exp_report_attrs": True,
154
+ "aggregate": "COUNT",
155
+ "y_axis_display_grid": True,
156
+ "score_color": f"{random.choice(colors)['sys_id']}", # default: "65b30218a9fe3dba0120df8611520d97"
157
+ "axis_max_color": f"{random.choice(colors)['sys_id']}", # default: "b0d449b3d7332100fa6c0c12ce610383"
158
+ "is_real_time": False,
159
+ "show_empty": False,
160
+ "direction": "minimize",
161
+ "display_grid": False,
162
+ "chart_border_width": "1",
163
+ "funnel_neck_percent": "30",
164
+ "show_legend": True,
165
+ "set_color": "one_color",
166
+ "color_palette": f"{color_palette_sys_id}", # default: "65b30218a9fe3dba0120df8611520d97"
167
+ "x_axis_label_size": "11",
168
+ "show_chart_border": False,
169
+ "x_axis_grid_dotted": False,
170
+ "chart_title_x_position": "0",
171
+ "pivot_expanded": True,
172
+ }
173
+
174
+ result = table_api_call(
175
+ instance=instance,
176
+ table="sys_report",
177
+ # The cmdb_model_category is the sys_id for the hardware category; computer in this case
178
+ json=report_params,
179
+ method="POST",
180
+ wait_for_record=True,
181
+ )["result"]
182
+
183
+ return result["sys_id"], plot_title
@@ -0,0 +1,63 @@
1
+ import faker
2
+
3
+ fake = faker.Faker()
4
+
5
+ from ..instance import SNowInstance
6
+ from .utils import table_api_call
7
+
8
+
9
+ def create_requested_item(
10
+ instance: SNowInstance,
11
+ user_sys_id: str,
12
+ system_name: str,
13
+ quantity: int = 1,
14
+ short_description: str = None,
15
+ ) -> list[str]:
16
+ """
17
+ Create a requested item for a given user
18
+
19
+ Parameters:
20
+ -----------
21
+ instance: SNowInstance
22
+ The instance to create the requested item in
23
+ user_sys_id: str
24
+ The sys_id of the user to request the item for
25
+ system_name: str
26
+ The name of the system to request (e.g. "Developer Laptop (Mac)" )
27
+ quantity: int
28
+ The quantity of the item to request
29
+ short_description: str
30
+ The short description of the item (optional). if not provided, a random one will be generated
31
+
32
+ Returns:
33
+ --------
34
+ sys_id, number of the requested item
35
+
36
+ """
37
+ if short_description is None:
38
+ short_description = fake.sentence(4)
39
+
40
+ item_sys_id = table_api_call(
41
+ instance=instance,
42
+ table="sc_cat_item",
43
+ params={"sysparm_query": f"sys_name={system_name}", "sysparm_fields": "sys_id"},
44
+ )["result"][0]["sys_id"]
45
+
46
+ item_config = {
47
+ "requested_for": user_sys_id,
48
+ "state": "3",
49
+ "impact": "3",
50
+ "active": "true",
51
+ "priority": "4",
52
+ "short_description": short_description,
53
+ "urgency": "3",
54
+ "quantity": str(quantity),
55
+ "billable": "false",
56
+ "cat_item": item_sys_id,
57
+ }
58
+
59
+ result = table_api_call(
60
+ instance=instance, table="sc_req_item", json=item_config, method="POST"
61
+ )["result"]
62
+
63
+ return result["sys_id"], result["number"]
@@ -1,5 +1,5 @@
1
- import random
2
1
  from faker import Faker
2
+ import numpy as np
3
3
  import time
4
4
 
5
5
  fake = Faker()
@@ -14,7 +14,9 @@ def create_user(
14
14
  first_name: str = None,
15
15
  last_name: str = None,
16
16
  user_name: str = None,
17
- admin=True,
17
+ return_full_response: bool = False,
18
+ user_roles: list[str] = ["admin"],
19
+ random: np.random = np.random,
18
20
  ) -> list[str]:
19
21
  """
20
22
  Create a user with a random username and password with an admin role
@@ -27,8 +29,8 @@ def create_user(
27
29
  The last name of the user, defaults to a random last name
28
30
  user_name: str
29
31
  The user name of the user, defaults to first_name.last_name
30
- admin: bool
31
- Whether to give the user admin permissions
32
+ user_roles: list[str]
33
+ The roles to assign to the user, defaults to ['admin']
32
34
 
33
35
  Returns:
34
36
  --------
@@ -56,12 +58,12 @@ def create_user(
56
58
  user_name = user_response["user_name"]
57
59
  user_sys_id = user_response["sys_id"]
58
60
 
59
- # Get admin role sys_id
60
- if admin:
61
+ # Get role sys_id's
62
+ for role in user_roles:
61
63
  role_sys_id = table_api_call(
62
64
  instance=instance,
63
65
  table="sys_user_role",
64
- params={"sysparm_query": "name=admin", "sysparm_fields": "sys_id"},
66
+ params={"sysparm_query": f"name={role}", "sysparm_fields": "sys_id"},
65
67
  method="GET",
66
68
  )["result"][0]["sys_id"]
67
69
 
@@ -77,7 +79,8 @@ def create_user(
77
79
  set_user_preference(
78
80
  instance, "glide.ui.polaris.theme.variant", theme["style.sys_id"], user=user_sys_id
79
81
  )
80
-
82
+ if return_full_response:
83
+ return user_response
81
84
  return user_name, user_password, user_sys_id
82
85
 
83
86
 
@@ -3,6 +3,7 @@ import requests
3
3
  from ..instance import SNowInstance
4
4
 
5
5
  from requests.exceptions import HTTPError
6
+ from time import sleep
6
7
 
7
8
  # ServiceNow API configuration
8
9
  SNOW_API_HEADERS = {"Content-Type": "application/json", "Accept": "application/json"}
@@ -15,12 +16,17 @@ def table_api_call(
15
16
  params: dict = {},
16
17
  json: dict = {},
17
18
  method: str = "GET",
19
+ wait_for_record: bool = False,
20
+ max_retries: int = 5,
21
+ raise_on_wait_expired: bool = True,
18
22
  ) -> dict:
19
23
  """
20
24
  Make a call to the ServiceNow Table API
21
25
 
22
26
  Parameters:
23
27
  -----------
28
+ instance: SNowInstance
29
+ The ServiceNow instance to interact with
24
30
  table: str
25
31
  The name of the table to interact with
26
32
  data: dict
@@ -31,6 +37,13 @@ def table_api_call(
31
37
  The JSON data to send with the request
32
38
  method: str
33
39
  The HTTP method to use (GET, POST, PUT, DELETE).
40
+ wait_for_record: bool
41
+ If True, will wait up to 2 seconds for the record to be present before returning
42
+ max_retries: int
43
+ The number of retries to attempt before failing
44
+ raise_on_wait_expired: bool
45
+ If True, will raise an exception if the record is not found after max_retries.
46
+ Otherwise, will return an empty result.
34
47
 
35
48
  Returns:
36
49
  --------
@@ -49,13 +62,44 @@ def table_api_call(
49
62
  params=params,
50
63
  json=json,
51
64
  )
65
+ if method == "POST":
66
+ sys_id = response.json()["result"]["sys_id"]
67
+ data = {}
68
+ params = {"sysparm_query": f"sys_id={sys_id}"}
52
69
 
53
- # Check for HTTP code 200 (fail otherwise)
70
+ # Check for HTTP success code (fail otherwise)
54
71
  response.raise_for_status()
55
72
 
73
+ record_exists = False
74
+ num_retries = 0
75
+ if method == "POST" or wait_for_record:
76
+ while not record_exists:
77
+ sleep(0.5)
78
+ get_response = table_api_call(
79
+ instance=instance,
80
+ table=table,
81
+ params=params,
82
+ json=json,
83
+ data=data,
84
+ method="GET",
85
+ )
86
+ record_exists = len(get_response["result"]) > 0
87
+ num_retries += 1
88
+ if num_retries > max_retries:
89
+ if raise_on_wait_expired:
90
+ raise HTTPError(f"Record not found after {max_retries} retries")
91
+ else:
92
+ return {"result": []}
93
+ if method == "GET":
94
+ response = get_response
95
+
56
96
  if method != "DELETE":
57
- # Decode the JSON response into a dictionary
58
- return response.json()
97
+ # Decode the JSON response into a dictionary if necessary
98
+ # When using wait_for_record=True, the response is already a dict as it is a recursive call
99
+ if type(response) == dict:
100
+ return response
101
+ else:
102
+ return response.json()
59
103
  else:
60
104
  return response
61
105
 
@@ -66,6 +66,10 @@ ORDER_LOANER_LAPTOP_TASK_CONFIG_PATH = str(
66
66
  # Knowledge base that is included with the benchmark
67
67
  KB_NAME = "General Knowledge"
68
68
  KB_FILEPATH = str(resources.files(data_files).joinpath("setup_files/knowledge/knowledge_base.json"))
69
+ PROTOCOL_KB_NAME = "Company Protocols"
70
+ PROTOCOL_KB_FILEPATH = str(
71
+ resources.files(data_files).joinpath("setup_files/knowledge/protocols.json")
72
+ )
69
73
 
70
74
  # Form tasks
71
75
  CREATE_CHANGE_REQUEST_CONFIG_PATH = str(
@@ -165,12 +169,25 @@ EXPECTED_CHANGE_REQUEST_COLUMNS_PATH = str(
165
169
  "setup_files/lists/expected_change_request_list_columns.json"
166
170
  )
167
171
  )
172
+ EXPECTED_EXPENSE_LINE_COLUMNS_PATH = str(
173
+ resources.files(data_files).joinpath(
174
+ "setup_files/lists/expected_expense_line_list_columns.json"
175
+ )
176
+ )
168
177
  EXPECTED_HARDWARE_COLUMNS_PATH = str(
169
178
  resources.files(data_files).joinpath("setup_files/lists/expected_hardware_list_columns.json")
170
179
  )
171
180
  EXPECTED_INCIDENT_COLUMNS_PATH = str(
172
181
  resources.files(data_files).joinpath("setup_files/lists/expected_incident_list_columns.json")
173
182
  )
183
+ EXPECTED_PROBLEM_COLUMNS_PATH = str(
184
+ resources.files(data_files).joinpath("setup_files/lists/expected_problem_list_columns.json")
185
+ )
186
+ EXPECTED_REQUESTED_ITEMS_COLUMNS_PATH = str(
187
+ resources.files(data_files).joinpath(
188
+ "setup_files/lists/expected_requested_items_list_columns.json"
189
+ )
190
+ )
174
191
  EXPECTED_SERVICE_CATALOG_COLUMNS_PATH = str(
175
192
  resources.files(data_files).joinpath(
176
193
  "setup_files/lists/expected_service_catalog_list_columns.json"
@@ -188,6 +205,7 @@ EXPECTED_CHANGE_REQUEST_FORM_FIELDS_PATH = str(
188
205
  "setup_files/forms/expected_change_request_form_fields.json"
189
206
  )
190
207
  )
208
+
191
209
  EXPECTED_HARDWARE_FORM_FIELDS_PATH = str(
192
210
  resources.files(data_files).joinpath("setup_files/forms/expected_hardware_form_fields.json")
193
211
  )
@@ -200,7 +218,9 @@ EXPECTED_PROBLEM_FORM_FIELDS_PATH = str(
200
218
  EXPECTED_USER_FORM_FIELDS_PATH = str(
201
219
  resources.files(data_files).joinpath("setup_files/forms/expected_user_form_fields.json")
202
220
  )
203
-
221
+ EXPECTED_REQUEST_ITEM_FORM_FIELDS_PATH = str(
222
+ resources.files(data_files).joinpath("setup_files/forms/expected_request_item_form_fields.json")
223
+ )
204
224
 
205
225
  # Report date filter patch flag
206
226
  REPORT_PATCH_FLAG = "WORKARENA_DATE_FILTER_PATCH"
@@ -1 +1 @@
1
- ["comments", "assigned_to", "assignment_group", "caller_id", "category", "caused_by", "rfc", "contact_type", "cmdb_ci", "description", "impact", "knowledge", "number", "hold_reason", "parent_incident", "priority", "problem_id", "close_code", "close_notes", "resolved_at", "resolved_by", "business_service", "service_offering", "short_description", "state", "subcategory", "route_reason", "universal_request", "urgency", "watch_list", "work_notes", "work_notes_list"]
1
+ ["comments", "assigned_to", "assignment_group", "caller_id", "category", "caused_by", "rfc", "contact_type", "cmdb_ci", "description", "impact", "knowledge", "number", "hold_reason", "parent_incident", "priority", "problem_id", "close_code", "close_notes", "resolved_at", "resolved_by", "business_service", "service_offering", "short_description", "state", "subcategory", "route_reason", "universal_request", "urgency", "watch_list", "work_notes", "work_notes_list"]
@@ -0,0 +1 @@
1
+ ["number", "cat_item", "request", "requested_for", "due_date", "configuration_item", "watch_list", "opened_at", "opened_by", "stage", "state", "quantity", "estimated_delivery", "backordered", "order_guide", "comments"]
@@ -0,0 +1,46 @@
1
+ [
2
+ {
3
+ "item": "Onboarding a new user",
4
+ "article": "<h2>Onboarding a new user</h2> <p>This document outlines the procedure for onboarding a new user within the company. Proper onboarding ensures that new users have the necessary tools and access to start their roles effectively and efficiently. Follow the steps below to complete the onboarding process.</p> <h2>Steps for Onboarding a New User</h2> <h3>1. Create a User Account</h3> <ol> <li>Access the user creation interface.</li> <li>Enter the required information for the new user.</li> <li>Save the new user account.</li> </ol> <p>You can create a user account <a href='./now/nav/ui/classic/params/target/sys_user_list.do'>here</a>.</p> <h3>2. Order a Laptop</h3> <ol> <li>Access the service catalog.</li> <li>Order an Apple MacBook Pro 15\" laptop for the new user.</li> <li>Confirm the order details and submit the request.</li> </ol> <p>You can order the laptop <a href='./now/nav/ui/classic/params/target/catalog_home.do%3Fsysparm_view%3Dcatalog_default'>here</a>.</p> <h3>3. Create a Hardware Asset</h3> <ol> <li>Access the hardware asset management interface.</li> <li>Create a new hardware asset with the required configuration.</li> <li>Assign the newly created hardware asset to the user.</li> </ol> <p>You can create and assign a hardware asset <a href='./now/nav/ui/classic/params/target/alm_hardware_list.do'>here</a>.</p> <h2>Conclusion</h2> <p>Following these steps will ensure that new users are properly onboarded with the necessary equipment and access rights. For any issues or additional assistance, please contact the IT department.</p> <hr> <p>This document serves as a guide to streamline the user onboarding process, ensuring consistency and efficiency across the organization.</p>"
5
+ },
6
+ {
7
+ "item": "Offboarding a user",
8
+ "article": "<h1>Offboarding a user</h1> <h2>Introduction</h2> <p>This document outlines the procedure for offboarding a user within the company. Proper offboarding ensures that company assets are secured and that the departing user's access is properly removed. Follow the steps below to complete the offboarding process.</p> <h2>Steps for Offboarding a User</h2> <h3>1. Un-assign Hardware Assets</h3> <ol> <li>Find the user's laptop by looking for the hardware asset assigned to them.</li> <li>Un-assign the laptop by erasing the \"Assigned to\" field.</li> </ol> <p>You can manage hardware assets <a href='./now/nav/ui/classic/params/target/alm_hardware_list.do'>in the hardware asset list</a>.</p> <h3>2. Delete the User Account</h3> <ol> <li>Access the user management interface.</li> <li>Locate and delete the user account.</li> </ol> <p>You can delete the user account <a href='./now/nav/ui/classic/params/target/sys_user_list.do'>here</a>.</p> <h2>Conclusion</h2> <p>Following these steps will ensure that departing users are properly offboarded and that all company assets and access rights are appropriately managed. For any issues or additional assistance, please contact the IT department.</p> <hr> <p>This document serves as a guide to streamline the user offboarding process, ensuring consistency and security across the organization.</p>"
9
+ },
10
+ {
11
+ "item": "Finding the warranty expiration for a user's laptop",
12
+ "article": "<h1>Finding the Warranty Expiration for a User's Laptop</h1> <h2>Introduction</h2> <p>This document outlines the procedure for finding the warranty expiration date of a user's laptop. Ensuring that the warranty information is up-to-date is crucial for managing hardware assets and planning for replacements or repairs.</p> <h2>Steps to Find the Warranty Expiration Date</h2> <h3>1. Locate the Laptop Assigned to the User</h3> <ol> <li>Find the laptop assigned to the user by looking at the \"Assigned to\" field <a href='./now/nav/ui/classic/params/target/alm_hardware_list.do'>in the hardware asset list</a>.</li> </ol> <h3>2. Find the Laptop's Warranty Expiration Date</h3> <ol> <li>Once the laptop is located, check the warranty expiration date on the asset details page.</li> </ol> <h2>Conclusion</h2> <p>Following these steps will help you accurately find the warranty expiration date of a user's laptop. For any issues or additional assistance, please contact the IT department.</p> <hr> <p>This document serves as a guide to ensure proper management of hardware warranties within the organization.</p>"
13
+ },
14
+ {
15
+ "item": "Agent Workload Balancing",
16
+ "article": "<h1>Agent Workload Balancing</h1> <h2>Introduction</h2> <p>Agent Workload Balancing is a process designed to distribute work evenly among agents by re-assigning tasks. The problems to re-distribute all contain specific hashtags in their problem statements. By balancing the workload, we ensure that no single agent is overwhelmed while others have fewer tasks. All problems can be found in the <a href='./now/nav/ui/classic/params/target/problem_list.do'>problem list</a>.</p> <h2>Steps for Agent Workload Balancing</h2> <h3>1. Identify Busiest and Least Busy Users</h3> <ol> <li>Among the problems with descriptions containing the required hashtag, identify the user with the most assigned problems and the user with the least assigned problems.</li> <li>This information can be found in the report named 'Problems with hashtag {hashtag_name}'.</li> </ol> <p>You can access the list of reports <a href='./now/nav/ui/classic/params/target/sys_report_list.do'>here</a>.</p> <h3>2. Find a Low Priority Problem</h3> <ol> <li>Locate a problem with the lowest priority (priority=5) that includes the appropriate hashtag in the problem statement and is assigned to the busiest user.</li> </ol> <p>You can filter <a href='./now/nav/ui/classic/params/target/problem_list.do'>the problem list</a> to find such a problem.</p> <h3>3. Re-assign the Problem</h3> <ol> <li>Re-assign the identified low priority problem to the least busy user.</li> </ol> <h2>Conclusion</h2> <p>Following these steps will help balance the workload among agents by re-assigning low priority problems from the busiest to the least busy user. For any issues or additional assistance, please contact the IT department.</p> <hr> <p>This document serves as a guide to ensure effective workload management among agents within the organization.</p>"
17
+ },
18
+ {
19
+ "item": "Work Assignment: Assign Incidents to Relevant Agents",
20
+ "article": "<h1>Work Assignment: Assign Incidents to Relevant Agents</h1> <h2>Introduction</h2> <p>This document outlines the process for assigning incidents to relevant agents based on both the category and the priority of the incident. Proper assignment ensures that incidents are handled by the most appropriate agents, leading to quicker and more effective resolutions. Follow these steps to assign incidents correctly.</p> <h2>Steps for Assigning Incidents</h2> <h3>1. Locate the Incident</h3> <ol> <li>Go to the incidents page and search for the incident using the incident number that needs to be assigned.</li> </ol> <p>You can access the incidents page <a href='./now/nav/ui/classic/params/target/incident_list.do'>here</a>.</p> <h3>2. Identify the Incident Category and Priority</h3> <ol> <li>Look at the category and priority of the incident. The category will be one of the following: 'Hardware', 'Software', 'Network', or 'Database'.</li> <li>Assign the incident to the category experts mentioned in the task description. </li> </ol> <h3>3. Assign the Incident</h3> <ol> <li>If applicable, assign the incident to the relevant agent based on the priority of the incident. The priority levels are as follows: <ul> <li><strong>Priority 1 - Critical:</strong> Assign to the 'expert' of the category.</li> <li><strong>Priority 3 - Moderate:</strong> Assign to the 'supporter' of the category.</li> <li><strong>Priority 5 - Planning:</strong> Assign to the 'planner' of the category.</li> </ul> </li> </ol> <h2>Conclusion</h2> <p>By following these steps, you can ensure that incidents are assigned to the most qualified agents based on their category and priority. This approach leads to faster resolution times and improved efficiency in incident management. For any issues or additional assistance, please contact the IT department.</p> <hr> <p>This document serves as a guide to ensure proper assignment of incidents to relevant agents within the organization.</p>"
21
+ },
22
+ {
23
+ "item": "Edit a knowledge article to manage incorrect information",
24
+ "article": "<h1>Edit a Knowledge Article to Manage Incorrect Information</h1> <h2>Introduction</h2> <p>This document outlines the procedure for editing a knowledge base article that contains incorrect, outdated, or obsolete information. Ensuring that all knowledge articles are accurate and up-to-date is crucial for maintaining the integrity and reliability of the knowledge base.</p> <h2>Steps to Edit a Knowledge Article</h2> <h3>1. Search the Knowledge Base</h3> <ol> <li>Search the knowledge base using the given query.</li> </ol> <p>You can perform the search <a href='./now/nav/ui/classic/params/target/%24knowledge.do'>here</a>.</p> <h3>2. Identify the Correct and Incorrect Articles</h3> <ol> <li>Identify the articles that contain the correct and incorrect information based on what the information should be.</li> </ol> <h3>3. Mark the Incorrect Article</h3> <ol> <li>Add a comment to the article to mark it as 'incorrect' and mention the 'number' of the correct article as per the task description.</li> </ol> <h3>4. Mark the Correct Article</h3> <ol> <li>Add a comment to the article to label it as 'correct' and mention the 'number' of the incorrect article as per the task description to avoid having misguiding people.</li> </ol> <h2>Conclusion</h2> <p>Following these steps will help maintain the accuracy and relevance of the knowledge base by properly marking and referencing articles with correct and incorrect information. For any issues or additional assistance, please contact the IT department.</p> <hr> <p>This document serves as a guide to ensure effective management of information within the knowledge base.</p>"
25
+ },
26
+ {
27
+ "item":"Problem List Cleanup",
28
+ "article": "<h1>Problem List Cleanup</h1> <h2>Introduction</h2> <p>Problem List Cleanup ensures that the problem list remains organized and free from redundancy. In the <a href='./now/nav/ui/classic/params/target/problem_list.do'>problem list</a>, some problem's \"Problem statement\" field contain a hashtag so we know which problem group they belong to. The problem list cleanup involves identifying problems with duplicated problem statements and marking them as duplicates. </p> <h2>Steps for Problem List Cleanup</h2> <h3>1. Identify Duplicated Problems</h3> <ol> <li>Among the problems with problem statements containing the required hashtag, identify those with duplicated problem statements. This can be done by filtering <a href='/now/nav/ui/classic/params/target/problem_list.do'>the problem list</a> .</li> </ol> <h3>2. Mark Duplicated Problems</h3> <ol> <li>If two problems have the same priority, you can mark either one as a duplicate of the other. Otherwise, mark the lowest priority problem as a duplicate of the highest priority one to keep the highest priority problems open. A problem's priority can range from 1 (Critical) to 5 (Planning), with 1 being the highest priority.</li> <li>Marking a problem as duplicate is done by opening the problem record and Clicking \"Mark Duplicate\".</li> </ol> <h3>3. Additional Handling for Critical Priority Problems</h3> <ol> <li>If you need to mark a priority 1 (Critical priority) problem as a duplicate of another, change the description of this problem to \"Duplicate\" to avoid further confusion.</li> </ol> <h2>Conclusion</h2> <p>Following these steps will help maintain a clean and efficient problem list by properly marking and managing duplicated problems. For any issues or additional assistance, please contact the IT department.</p> <hr> <p>This document serves as a guide to ensure effective problem management within the organization.</p>"
29
+ },
30
+ {
31
+ "item": "Scheduling Your Change Requests",
32
+ "article": "<h1>Scheduling Your Change Requests</h1> <h2>Introduction</h2> <p>Scheduling change requests is a critical process in managing IT infrastructure and operations. This process involves organizing and prioritizing change requests to ensure they are implemented efficiently and with minimal disruption to ongoing operations. Change requests often include updates, fixes, or enhancements that need to be scheduled within specific time blocks. The following guidelines outline how to create a valid schedule for change requests. As a first step, we note that change requests are grouped by hashtags placed in their short description. In general, creating a schedule is done for change requests that share a given hashtag and by setting the \"Planned start date\" and \"Planned end date\" for these change requests. Make sure to leave empty the \"Actual start date\" and \"Actual end date\" as they should only be filled when the work has started. All change requests can be found <a href='./now/nav/ui/classic/params/target/change_request_list.do'>here</a>. </p> <h2>Scheduling Rules</h2> <h3>1. Time Constraints</h3> <ol> <li>All change requests must be scheduled within the allowed time frame. They should not start before the start of the schedule block and must end before it closes. Moreover, they should not overlap.</li> </ol> <h3>2. Impact Order</h3> <ol> <li>Higher impact change requests must be scheduled before lower impact ones, ensuring the schedule prioritizes more significant changes.</li> </ol> <h3>3. Consecutive Requests</h3> <ol> <li>Generally, there should be no more than one day between consecutive change requests.</li> <li>If the change requests are required to follow a \"tight\" schedule, there should be no more than one hour between consecutive requests.</li> </ol> <h3>4. Duration Compliance</h3> <ol> <li>All change requests must respect the desired durations, which are determined by the risk level: <ul> <li>High risk: 3 days</li> <li>Moderate risk: 2 days</li> <li>Low risk: 1 day</li> </ul> </li> </ol> <h2>Conclusion</h2> <p>Following these guidelines will help you create an efficient and effective schedule for your change requests, minimizing disruptions and prioritizing higher impact changes. For any issues or additional assistance, please contact the IT department.</p> <hr> <p>This document serves as a guide to ensure proper scheduling and management of change requests within the organization.</p>"
33
+ },
34
+ {
35
+ "item": "Managing Your Existing Expenses",
36
+ "article": "<h1>Managing Your Existing Expenses</h1> <h2>Introduction</h2> <p>Managing your existing expenses is a crucial aspect of maintaining financial accuracy and compliance within the company. This process involves reviewing expense lines to ensure no duplicates remain. Expense lines can be found <a href='./now/nav/ui/classic/params/target/fm_expense_line_list.do'>here</a>. Duplicate expenses can lead to inaccuracies in financial reporting and budget management, making it essential to handle them according to established guidelines. Expense lines normally contain specific hashtags so they can be grouped. The process of filtering the duplicates is done for specific hashtags. </p> <h2>Steps for Managing Expense Duplicates</h2> <h3>1. Identify Duplicate Expenses</h3> <ol> <li>Review expense lines with short descriptions containing the given hashtag.</li> <li>Identify expense lines that have the same short description, which are considered duplicates.</li> </ol> <h3>2. Apply Rules to Handle Duplicates</h3> <ol> <li>Among duplicates, keep only those linked to tasks (e.g., Change Request, Incident) and delete the others.</li> <li>If all duplicates are linked to tasks, or none are linked to tasks, keep only the oldest one.</li> <li>If all duplicates have the same date, keep only the most expensive one.</li> <li>Finally, if all duplicates have the same cost, you can keep any of the expenses.</li> </ol> <h2>Conclusion</h2> <p>Following these guidelines will help you manage your existing expenses effectively, ensuring compliance with company policies and maintaining accurate financial records. For any issues or additional assistance, please contact the finance department.</p> <hr> <p>This document serves as a guide to ensure proper management of expenses within the organization.</p>"
37
+ },
38
+ {
39
+ "item": "Maximizing total investment return",
40
+ "article": "<h1>Maximizing Total Investment Return</h1><h2>Introduction</h2><p>Investment projects are filed as expense lines and are tagged with project IDs (hashtags) so they can be grouped. Expense lines can be found <a href='./now/nav/ui/classic/params/target/fm_expense_line_list.do'>here</a>. Maximizing total investment return involves reviewing these expense lines and selecting the ones that maximize revenue while fitting within the allowed budget. The investment's returns are specified in their short descriptions and their costs appear in their \"Amount\" field. Depending on the specifics of the task, you may be required to provide different types of information.</p><h2>Steps for Maximizing Total Investment Return</h2><h3>1. Review Expense Lines</h3><ol> <li>Identify expense lines with short descriptions containing the given hashtag.</li> <li>Evaluate the returns based on the short description and costs based on the \"Amount\" field to determine their suitability based on the allowed budget.</li></ol><h3>2. Provide Required Information</h3><p>Depending on the task requirements, you may need to provide one or more of the following:</p><ul> <li><strong>Total Return of Selected Investments Only:</strong> If requested, provide only the total return of the selected investments in the chat.</li> <li><strong>Selected Investments Only:</strong> If requested, provide the values for the \"Number\" field of the selected investments in the chat.</li> <li><strong>Selected Investments and Total Return:</strong> If requested, provide the values for the \"Number\" field of the selected investments as well as their total return in the chat.</li> <li><strong>Investment Lines Cleanup:</strong> If requested, delete the investments that will not be kept so that only the selected investments remain.</li></ul><h2>Conclusion</h2><p>Following these steps will help you allocate investments effectively, ensuring that the selected projects maximize revenue while adhering to the budget constraints. For any issues or additional assistance, please contact the finance department.</p><hr><p>This document serves as a guide to ensure proper management and allocation of investments within the organization.</p>"
41
+ },
42
+ {
43
+ "item": "Dashboard Retrieve Information and Perform Task",
44
+ "article": "<h1>Dashboard Retrieve Information and Perform Task</h1><h2>Introduction</h2><p>Dashboards consists of either bar plots or pie charts containing important information, generally as a pair of some text and numbers. You would be asked to retrieve some information from the chart, which might be retrieving values such as the maximum and minimum value or requiring standard mathematical calculations such as mean, median, and mode. You may also require to extract the text associated with these values, such as the name of an agent. Once they are retrieved, you would be requested to perform a task using this information. Please note that we round off everything to the next <i>highest</i> integer and treat it as the 'value' for the task. For calculations having more than one possible answer (such as 'mode' or 'most frequent' values), we consider the greatest number as the value or information.</p><h2>Steps for performing dashboard retrieval tasks</h2><h3>1. Retrieve information from the dashboard</h3><ol><li>Go to Reports > View/Run in the all menu. You can go to the page <a href='./now/nav/ui/classic/params/target/report_home.do%3Fjvar_selected_tab%3DmyReports'>here</a> as well.</li><li>Use the hashtag given in the task description to filter out the required dashboard chart and navigate to it.</li><li>Based on the task description, you will be given a 'value' field. This would mention if you need to fetch the minimum or maximum valued information or the mean, median, or the mode.</li><li>In certain cases, the description will also mention if you need to perform the following task by considering 'greater than or equal to' or 'lesser than or equal to' values for the retrieved information.</li></ol><p> This is the retrieved information from the dashboard.</p><h3>2. Perform the task</h3><p>After retrieving the information, you would be given a task to solve. Depending on the task requirements, you may need to perform one or more of the following:</p><ul><li><strong>Create form entries:</strong> Fill forms with the given information. Only fill the fields mentioned in the task description.</li><li><strong>Filter lists:</strong> Filter the lists using the attribute mentioned in the task description and following the retrieved information.</li><li><strong>Order items:</strong> You would need to go to the service catalog and order an item after making some calculations of the quantity as per the task description.</li></ul><p>The following links may be helpful for achieving the above tasks:</p><ul><li>Create <a href='./now/nav/ui/classic/params/target/incident_list.do'>incidents</a>, <a href='./now/nav/ui/classic/params/target/problem_list.do'>problems</a> or <a href='./now/nav/ui/classic/params/target/sc_req_item_list.do'>item requests</a></li><li>Lists: <a href='./now/nav/ui/classic/params/target/alm_asset_list.do'>asset list</a>, <a href='./now/nav/ui/classic/params/target/alm_hardware_list.do'>hardware list</a>, <a href='./now/nav/ui/classic/params/target/incident_list.do'>incident list</a>, <a href='./now/nav/ui/classic/params/target/sys_user_list.do'>user list</a></li> <li><a href='./now/nav/ui/classic/params/target/catalog_home.do%3Fsysparm_view%3Dcatalog_default'>Service catalog</a> for ordering items</li></ul><h2>Conclusion</h2><p>Following these steps will help you achieve the task of retrieving information from a dashboard and using it to solve another task.</p><hr><p>This document serves as a guide to ensure proper management and allocation of investments within the organization.</p>"
45
+ }
46
+ ]
@@ -0,0 +1 @@
1
+ <h2>Dispatching problems</h2>\n<p>Dispatching problems involves taking problems under a given category and re-assigning one low priority from the busiest to the least busy user.To do so, you need to:</p>\n<ul>\n<li> Find the user that has the most problems assigned to them and the one that has the least number of problems assigned to them. This is done by finding the information in the report for the given category, which is named 'Problems for category {category_name}'. The list of reports can be found <a href='./now/nav/ui/classic/params/target/sys_report_list.do'> here </a> </li>\n<li> Find a lowest priority problem (priority=5) of the appropriate category assigned to the user. This can be done by filtering <a href='./now/nav/ui/classic/params/target/problem_list.do'> the problem list </a> </li>\n<li> Assign this problem to the least busy user </li></ul>
@@ -1,34 +1,12 @@
1
1
  [
2
+ "asset_tag",
2
3
  "model.display_name",
3
4
  "model_category",
4
- "asset_tag",
5
- "substatus",
6
- "asset_function",
7
- "install_status",
8
5
  "sys_class_name",
9
6
  "assigned_to",
10
- "serial_number",
11
7
  "location",
12
- "vendor",
13
- "assigned",
14
8
  "company",
15
- "cost",
16
9
  "department",
17
- "display_name",
18
- "model",
19
- "sys_updated_by",
20
- "sys_updated_on",
21
- "sys_mod_count",
22
- "retirement_date",
23
- "retired",
24
- "residual",
25
- "quantity",
26
- "purchase_date",
27
- "po_number",
28
- "order_date",
29
- "delivery_date",
30
- "managed_by",
31
- "invoice_number",
32
- "cost_center",
10
+ "install_status",
33
11
  "warranty_expiration"
34
12
  ]
@@ -1,48 +1,12 @@
1
1
  [
2
2
  "number",
3
3
  "short_description",
4
- "chg_model",
5
- "type",
6
- "state",
7
4
  "risk",
5
+ "impact",
6
+ "priority",
7
+ "assigned_to",
8
8
  "start_date",
9
9
  "end_date",
10
- "requested_by",
11
- "assignment_group",
12
- "assigned_to",
13
- "sys_created_on",
14
- "active",
15
- "work_end",
16
- "work_start",
17
- "approval",
18
- "approval_history",
19
- "approval_set",
20
- "backout_plan",
21
- "category",
22
- "change_plan",
23
- "close_code",
24
- "close_notes",
25
- "closed_at",
26
- "closed_by",
27
- "cmdb_ci",
28
- "conflict_last_run",
29
- "conflict_status",
30
- "contact_type",
31
- "sys_created_by",
32
- "delivery_plan",
33
- "delivery_task",
34
- "description",
35
- "task_effective_number",
36
- "escalation",
37
- "impact",
38
10
  "implementation_plan",
39
- "justification",
40
- "knowledge",
41
- "made_sla",
42
- "opened_at",
43
- "opened_by",
44
- "phase",
45
- "phase_state",
46
- "priority",
47
- "reassignment_count"
11
+ "approval"
48
12
  ]
@@ -0,0 +1,12 @@
1
+ [
2
+ "number",
3
+ "user",
4
+ "inherited",
5
+ "parent",
6
+ "date",
7
+ "short_description",
8
+ "source_id",
9
+ "amount",
10
+ "type",
11
+ "summary_type"
12
+ ]