Skip to content

Commit 85954b2

Browse files
authored
Completed UI changes to download V2 JSON (#1204)
1 parent 99b0a4b commit 85954b2

8 files changed

Lines changed: 92 additions & 19 deletions

File tree

app/airflow/dags/libs/rules_export/core.py

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,22 @@ def pre_process_rules(**kwargs) -> None:
4040
validated_params = pull_validated_params(kwargs, "validate_params_rules_export")
4141
scan_report_id = validated_params["scan_report_id"]
4242
file_type = validated_params["file_type"]
43+
44+
# Map file types to temp table suffixes
45+
if file_type in ["application/json_v1", "application/json_v2"]:
46+
temp_table_suffix = "json"
47+
elif file_type == "csv":
48+
temp_table_suffix = "csv"
49+
else:
50+
temp_table_suffix = file_type
51+
4352
try:
4453
# Create or update the temp table with the processed rules data
4554
pg_hook.run(
4655
create_update_temp_rules_table_query
4756
% {
4857
"scan_report_id": scan_report_id,
49-
"file_type": file_type,
58+
"file_type": temp_table_suffix,
5059
},
5160
)
5261
except Exception as e:
@@ -70,6 +79,9 @@ def build_and_upload_rules_file(**kwargs) -> None:
7079
user_id = validated_params["user_id"]
7180
scan_report_name = validated_params["scan_report_name"]
7281
file_type = validated_params["file_type"]
82+
json_version = validated_params.get(
83+
"json_version", "v1"
84+
) # default to v1 if not specified
7385

7486
try:
7587
# Setup file config. (Credit: @AndyRae)
@@ -79,13 +91,27 @@ def build_and_upload_rules_file(**kwargs) -> None:
7991
"mapping_csv",
8092
"csv",
8193
),
94+
"application/json_v1": FileHandlerConfig(
95+
lambda: build_rules_json(scan_report_name, scan_report_id),
96+
"mapping_json",
97+
"json",
98+
),
99+
"application/json_v2": FileHandlerConfig(
100+
lambda: build_rules_json_v2(scan_report_name, scan_report_id),
101+
"mapping_json_v2",
102+
"json",
103+
),
82104
"json": FileHandlerConfig(
83105
lambda: (
84106
build_rules_json_v2(scan_report_name, scan_report_id)
85107
if AIRFLOW_VAR_JSON_VERSION == "v2"
86108
else build_rules_json(scan_report_name, scan_report_id)
87109
),
88-
"mapping_json",
110+
(
111+
"mapping_json_v2"
112+
if AIRFLOW_VAR_JSON_VERSION == "v2"
113+
else "mapping_json"
114+
),
89115
"json",
90116
),
91117
}
@@ -97,7 +123,11 @@ def build_and_upload_rules_file(**kwargs) -> None:
97123
file_extension = config.file_extension
98124

99125
# build file name
100-
filename = f"Rules - {scan_report_name} - {scan_report_id} - {datetime.now()}.{file_extension}"
126+
if file_type in ["application/json_v1", "application/json_v2"]:
127+
version = "V1" if file_type == "application/json_v1" else "V2"
128+
filename = f"Rules - {scan_report_name} - {scan_report_id} - {version} - {datetime.now()}.{file_extension}"
129+
else:
130+
filename = f"Rules - {scan_report_name} - {scan_report_id} - {datetime.now()}.{file_extension}"
101131

102132
# Upload to blob storage
103133
upload_blob_to_storage(
@@ -146,7 +176,11 @@ def build_and_upload_rules_file(**kwargs) -> None:
146176
"DROP TABLE IF EXISTS temp_rules_export_%(scan_report_id)s_%(file_type)s"
147177
% {
148178
"scan_report_id": scan_report_id,
149-
"file_type": file_type,
179+
"file_type": (
180+
"json"
181+
if file_type in ["application/json_v1", "application/json_v2"]
182+
else file_type
183+
),
150184
}
151185
)
152186
except Exception as e:
@@ -159,7 +193,7 @@ def build_and_upload_rules_file(**kwargs) -> None:
159193
)
160194
raise e
161195
except Exception as e:
162-
logging.error(f"Error creating file entry: {str(e)}")
196+
logging.error(f"Error building and uploading rules file: {str(e)}")
163197
update_job_status(
164198
scan_report=scan_report_id,
165199
stage=JobStageType.DOWNLOAD_RULES,

app/airflow/dags/libs/utils.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,12 +270,19 @@ def _validate_dag_params(
270270
if param == "file_type":
271271
if value == "application/json":
272272
value = "json"
273+
elif value == "application/json_v1":
274+
value = "application/json_v1"
275+
elif value == "application/json_v2":
276+
value = "application/json_v2"
273277
elif value == "text/csv":
274278
value = "csv"
275279
else:
276280
errors.append(
277-
f"Invalid {param}: {value}. Must be application/json or text/csv."
281+
f"Invalid {param}: {value}. Must be application/json, application/json_v1, application/json_v2, or text/csv."
278282
)
283+
elif param == "json_version":
284+
if value not in ["v1", "v2"]:
285+
errors.append(f"Invalid {param}: {value}. Must be v1 or v2.")
279286
validated_params[param] = value
280287

281288
# Validate boolean parameters
@@ -357,7 +364,7 @@ def validate_params_SR_processing(**context):
357364
def validate_params_rules_export(**context):
358365
"""Validates parameters required for rules export DAG tasks."""
359366
int_params = ["scan_report_id", "user_id"]
360-
string_params = ["file_type", "scan_report_name"]
367+
string_params = ["file_type", "scan_report_name", "json_version"]
361368
return _validate_dag_params(
362369
int_params=int_params,
363370
string_params=string_params,

app/api/files/fixtures/filetypes.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"display_name": "Mapping Rules JSON"
88
}
99
},
10+
1011
{
1112
"model": "files.filetype",
1213
"pk": 2,
@@ -38,5 +39,13 @@
3839
"value": "data_dictionary",
3940
"display_name": "Data Dictionary"
4041
}
42+
},
43+
{
44+
"model": "files.filetype",
45+
"pk": 6,
46+
"fields": {
47+
"value": "mapping_json_v2",
48+
"display_name": "Mapping Rules JSON V2"
49+
}
4150
}
4251
]

app/api/files/views.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ def post(self, request, *args, **kwargs):
7777
- scan_report_id (int): The ID of the scan report for which the
7878
file is to be generated.
7979
- file_type (str): The type of file to generate (e.g.,
80-
'application/json' or 'text/csv').
80+
'application/json_v1', 'application/json_v2', or 'text/csv').
8181
8282
Upon successful validation of the input, a message is sent to the
8383
Rules Export Queue, and a job record is created in the database to
@@ -111,20 +111,35 @@ def post(self, request, *args, **kwargs):
111111
)
112112
# Get the scan report model to get the scan report name for both Azure and Airflow tasks later on
113113
scan_report = ScanReport.objects.get(id=scan_report_id)
114+
115+
# Determine the JSON version for the message
116+
json_version = "v1" # default
117+
if file_type == "application/json_v2":
118+
json_version = "v2"
119+
elif file_type == "application/json_v1":
120+
json_version = "v1"
121+
114122
msg = {
115123
"scan_report_id": scan_report_id,
116124
"scan_report_name": scan_report.dataset,
117125
"user_id": request.user.id,
118126
"file_type": file_type,
127+
"json_version": json_version,
119128
}
120129

121130
worker_service.trigger_rules_export(msg)
131+
122132
# Create job record for downloading file
133+
file_type_description = (
134+
"JSON V1"
135+
if file_type == "application/json_v1"
136+
else "JSON V2" if file_type == "application/json_v2" else "CSV"
137+
)
123138
Job.objects.create(
124139
scan_report=ScanReport.objects.get(id=scan_report_id),
125140
stage=JobStage.objects.get(value="DOWNLOAD_RULES"),
126141
status=StageStatus.objects.get(value="IN_PROGRESS"),
127-
details=f"A Mapping Rules {'JSON' if file_type == 'application/json' else 'CSV'} is being generated.",
142+
details=f"A Mapping Rules {file_type_description} is being generated.",
128143
)
129144
except json.JSONDecodeError:
130145
return JsonResponse({"error": "Invalid JSON data."}, status=400)

app/next-client-app/app/(protected)/scanreports/[id]/actions-download-menu.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ type Props = { scanreportId: string };
1515
export function ActionsDownloadMenu({ scanreportId }: Props) {
1616
const router = useRouter();
1717

18-
const handleDownload = async (fileType: FileTypeFormat) => {
18+
const handleDownload = async (
19+
fileType: FileTypeFormat | "application/json_v1" | "application/json_v2"
20+
) => {
1921
const resp = await requestFile(Number(scanreportId), fileType);
2022
if (resp.success) {
2123
router.push(`/scanreports/${scanreportId}/downloads`);
@@ -30,10 +32,14 @@ export function ActionsDownloadMenu({ scanreportId }: Props) {
3032
return (
3133
<DropdownMenuGroup>
3234
<DropdownMenuLabel>Downloads</DropdownMenuLabel>
33-
<DropdownMenuItem onSelect={() => handleDownload("application/json")}>
35+
<DropdownMenuItem onSelect={() => handleDownload("application/json_v1")}>
3436
<FileJson />
3537
Mapping JSON
3638
</DropdownMenuItem>
39+
<DropdownMenuItem onSelect={() => handleDownload("application/json_v2")}>
40+
<FileJson />
41+
Mapping JSON V2
42+
</DropdownMenuItem>
3743
<DropdownMenuItem onSelect={() => handleDownload("text/csv")}>
3844
<FileSpreadsheet />
3945
Mapping CSV

app/next-client-app/app/(protected)/scanreports/[id]/downloads/columns.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export const columns: ColumnDef<FileDownload>[] = [
2626
return format(created_at, "d MMM HH:mm");
2727
},
2828
enableHiding: true,
29-
enableSorting: true,
29+
enableSorting: true
3030
},
3131
{
3232
id: "User",
@@ -43,7 +43,7 @@ export const columns: ColumnDef<FileDownload>[] = [
4343
return <>{user.username}</>;
4444
},
4545
enableHiding: true,
46-
enableSorting: false,
46+
enableSorting: false
4747
},
4848
{
4949
id: "Type",
@@ -60,7 +60,7 @@ export const columns: ColumnDef<FileDownload>[] = [
6060
return <Badge variant="outline">{file_type.display_name}</Badge>;
6161
},
6262
enableHiding: true,
63-
enableSorting: false,
63+
enableSorting: false
6464
},
6565
{
6666
id: "Download",
@@ -85,6 +85,6 @@ export const columns: ColumnDef<FileDownload>[] = [
8585
);
8686
},
8787
enableHiding: true,
88-
enableSorting: false,
89-
},
88+
enableSorting: false
89+
}
9090
];

app/next-client-app/components/recommendations/stored-recommendations-button.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ export function StoredRecommendationsButton({
111111
>
112112
<Sparkles className="h-4 w-4 text-purple-500" />
113113
{mappingRecommendations && mappingRecommendations.length > 0
114-
? `Recommendations (${mappingRecommendations.length})`
114+
? "Recommendations"
115115
: "No Recommendations"}
116116
</Button>
117117
</div>

app/next-client-app/types/files.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
1-
type FileTypeFormat = "application/json" | "image/svg+xml" | "text/csv";
1+
2+
type FileTypeFormat = "application/json" | "application/json_v1" | "application/json_v2" | "image/svg+xml" | "text/csv";
23
type FileTypeValue =
34
| "mapping_json"
5+
| "mapping_json_v2"
46
| "mapping_csv"
57
| "mapping_svg"
68
| "data_dictionary"
79
| "scan_report";
8-
910
interface FileType {
1011
value: FileTypeValue;
1112
display_name:
1213
| "Mapping Rules JSON"
14+
| "Mapping Rules JSON V2"
1315
| "Mapping Rules CSV"
1416
| "Mapping Rules SVG"
1517
| "Data Dictionary"

0 commit comments

Comments
 (0)