Skip to content

Commit 08de4f8

Browse files
dmitriy-borzenkoDmitriy Borzenko
and
Dmitriy Borzenko
authored
Kamu UI 464 query explainer successfully validates commitment but shows no data (#465)
* Extended logic of the reproduced result component * Fixed unit tests * changed CHANGELOG.md * improved reading from storage * Fixed PR comments * Added layout without uploaded token * Fixed PR comments * Fixed unit tests * changed route * Fixed PR comments * added unit tests * minor changes --------- Co-authored-by: Dmitriy Borzenko <[email protected]>
1 parent b414140 commit 08de4f8

25 files changed

+343
-168
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## Unreleased
99
### Fixed
10+
- Query explainer successfully validates commitment and shows data
1011
- Simplify the language in flow scheduling
1112

1213
## [0.28.2] - 2024-10-25

src/app/app.module.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ import { AccountComponent } from "./account/account.component";
7272
import { DatasetsTabComponent } from "./account/additional-components/datasets-tab/datasets-tab.component";
7373
import { AccessTokensTabComponent } from "./auth/settings/tabs/access-tokens-tab/access-tokens-tab.component";
7474
import { MatSlideToggleModule } from "@angular/material/slide-toggle";
75-
import { AutofocusDirective } from "./common/directives/autofocus.directive";
7675
import { DynamicTableModule } from "./components/dynamic-table/dynamic-table.module";
76+
import { AutofocusModule } from "./common/directives/autofocus.module";
7777

7878
const Services = [
7979
{
@@ -205,7 +205,6 @@ const MatModules = [
205205
AdminDashboardComponent,
206206
AccessTokensTabComponent,
207207
AccountFlowsTabComponent,
208-
AutofocusDirective,
209208
],
210209
imports: [
211210
AppRoutingModule,
@@ -247,6 +246,7 @@ const MatModules = [
247246
}), // ToastrModule added
248247
DatasetFlowDetailsModule,
249248
DynamicTableModule,
249+
AutofocusModule,
250250
],
251251
providers: [...Services],
252252
bootstrap: [AppComponent],
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { NgModule } from "@angular/core";
2+
import { CommonModule } from "@angular/common";
3+
import { AutofocusDirective } from "./autofocus.directive";
4+
5+
@NgModule({
6+
declarations: [AutofocusDirective],
7+
imports: [CommonModule],
8+
exports: [AutofocusDirective],
9+
})
10+
export class AutofocusModule {}

src/app/dataset-view/additional-components/data-component/data.component.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ describe("DataComponent", () => {
220220
});
221221

222222
it("should check click on `Verify query result` button", () => {
223-
const processQuerySpy = spyOn(queryExplainerService, "processQuery").and.returnValue(
223+
const processQuerySpy = spyOn(queryExplainerService, "processQueryWithProof").and.returnValue(
224224
of(mockQueryExplainerResponse),
225225
);
226226
const uploadFilePrepareSpy = spyOn(fileUploadService, "uploadFilePrepare").and.returnValue(

src/app/dataset-view/additional-components/data-component/data.component.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import { AppConfigService } from "src/app/app-config.service";
3333
import { UploadPrepareData, UploadPrepareResponse } from "src/app/common/ingest-via-file-upload.types";
3434
import { FileUploadService } from "src/app/services/file-upload.service";
3535
import { QueryExplainerService } from "src/app/query-explainer/query-explainer.service";
36-
import { QueryExplainerResponse } from "src/app/query-explainer/query-explainer.types";
36+
import { QueryExplainerProofResponse } from "src/app/query-explainer/query-explainer.types";
3737

3838
@Component({
3939
selector: "app-data",
@@ -173,9 +173,9 @@ export class DataComponent extends BaseComponent implements OnInit {
173173
public verifyQueryResult(): void {
174174
let uploadToken: string;
175175
this.queryExplainerService
176-
.processQuery(this.sqlRequestCode)
176+
.processQueryWithProof(this.sqlRequestCode)
177177
.pipe(
178-
switchMap((response: QueryExplainerResponse) => {
178+
switchMap((response: QueryExplainerProofResponse) => {
179179
const file = new File(
180180
[
181181
new Blob([JSON.stringify(response, null, 2)], {

src/app/dataset-view/dataset.service.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ import { DatasetApi } from "../api/dataset.api";
3939
import { DatasetNotFoundError } from "../common/errors";
4040
import { map } from "rxjs/operators";
4141
import { MaybeNull } from "../common/app.types";
42-
import { parseCurrentSchema } from "../common/app.helpers";
42+
import { parseCurrentSchema, removeAllLineBreaks } from "../common/app.helpers";
4343
import { APOLLO_OPTIONS } from "apollo-angular";
4444
import { resetCacheHelper } from "../apollo-cache.helper";
4545

@@ -430,6 +430,6 @@ export class DatasetService {
430430
}
431431

432432
private static parseSchema(schemaContent: string): DatasetSchema {
433-
return JSON.parse(schemaContent) as DatasetSchema;
433+
return JSON.parse(removeAllLineBreaks(schemaContent)) as DatasetSchema;
434434
}
435435
}

src/app/project-links.ts

+6-4
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,20 @@ import { Injectable } from "@angular/core";
22

33
@Injectable()
44
export default class ProjectLinks {
5-
public static readonly URL_HOME: string = "/";
6-
public static readonly URL_LOGIN: string = "v/login";
75
public static readonly URL_GITHUB_CALLBACK: string = "github_callback";
86
public static readonly URL_BLOCK: string = "block";
7+
public static readonly URL_FLOW_DETAILS: string = "flow-details";
8+
9+
// initial routes
10+
public static readonly URL_HOME: string = "/";
11+
public static readonly URL_LOGIN: string = "v/login";
912
public static readonly URL_SEARCH: string = "v/search";
1013
public static readonly URL_DATASET_CREATE: string = "v/new-dataset";
1114
public static readonly URL_PAGE_NOT_FOUND: string = "v/page-not-found";
1215
public static readonly URL_RETURN_TO_CLI: string = "v/return-to-cli";
1316
public static readonly URL_SETTINGS: string = "v/settings";
1417
public static readonly URL_ADMIN_DASHBOARD: string = "v/admin-dashboard";
15-
public static readonly URL_FLOW_DETAILS: string = "flow-details";
16-
public static readonly URL_QUERY_EXPLAINER: string = "query-explainer";
18+
public static readonly URL_QUERY_EXPLAINER: string = "v/query-explainer";
1719

1820
public static readonly ALL_URLS: string[] = [
1921
ProjectLinks.URL_HOME,

src/app/query-explainer/components/commitment-data-section/commitment-data-section.component.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { ChangeDetectionStrategy, Component, inject, Input } from "@angular/core";
2-
import { QueryExplainerComponentData, VerifyQueryError, VerifyQueryKindError } from "../../query-explainer.types";
2+
import { VerifyQueryError, VerifyQueryKindError } from "../../query-explainer.types";
33
import { Clipboard } from "@angular/cdk/clipboard";
44
import { changeCopyIcon } from "src/app/common/app.helpers";
55
import { MaybeUndefined } from "src/app/common/app.types";
6+
import { QueryExplainerComponentData } from "../../query-explainer.component";
67
@Component({
78
selector: "app-commitment-data-section",
89
templateUrl: "./commitment-data-section.component.html",

src/app/query-explainer/components/input-data-section/input-data-section.component.html

+7-3
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,23 @@
1313
>
1414
<div class="fw-semibold">Query dialect:</div>
1515
<div data-test-id="input-query-dialect">
16-
{{ inputParamsHelper(inputData.sqlQueryExplainerResponse.input.queryDialect) }}
16+
{{ inputData.sqlQueryExplainerResponse.input.queryDialect }}
1717
</div>
1818
</div>
1919
<div class="my-4 mx-4 d-flex flex-row justify-content-between">
2020
<div class="fw-semibold">Data format:</div>
2121
<div data-test-id="input-data-format">
22-
{{ inputParamsHelper(inputData.sqlQueryExplainerResponse.input.dataFormat) }}
22+
{{ inputData.sqlQueryExplainerResponse.input.dataFormat! }}
2323
</div>
2424
</div>
2525
<div class="my-4 mx-4 d-flex flex-row justify-content-between">
2626
<div class="fw-semibold">Schema format:</div>
2727
<div data-test-id="input-schema-format">
28-
{{ inputParamsHelper(inputData.sqlQueryExplainerResponse.input.schemaFormat!) }}
28+
{{
29+
inputData.sqlQueryExplainerResponse.input.schemaFormat
30+
? inputData.sqlQueryExplainerResponse.input.schemaFormat
31+
: "N/A"
32+
}}
2933
</div>
3034
</div>
3135
<div class="my-4 mx-4 d-flex flex-row justify-content-between">

src/app/query-explainer/components/input-data-section/input-data-section.component.spec.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,11 @@ describe("InputDataSectionComponent", () => {
7676
it("should check display data", () => {
7777
fixture.detectChanges();
7878
const queryDialectElem = findElementByDataTestId(fixture, "input-query-dialect");
79-
expect(queryDialectElem?.innerText.trim()).toEqual("SQL DataFusion");
79+
expect(queryDialectElem?.innerText.trim()).toEqual("SqlDataFusion");
8080
const dataFormatElem = findElementByDataTestId(fixture, "input-data-format");
81-
expect(dataFormatElem?.innerText.trim()).toEqual("JSON AoA");
81+
expect(dataFormatElem?.innerText.trim()).toEqual("JsonAoA");
8282
const schemaElem = findElementByDataTestId(fixture, "input-schema-format");
83-
expect(schemaElem?.innerText.trim()).toEqual("Arrow JSON");
83+
expect(schemaElem?.innerText.trim()).toEqual("ArrowJson");
8484
const limitElem = findElementByDataTestId(fixture, "input-limit");
8585
expect(limitElem?.innerText.trim()).toEqual("100");
8686
const skipElem = findElementByDataTestId(fixture, "input-skip");

src/app/query-explainer/components/input-data-section/input-data-section.component.ts

+1-16
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { ChangeDetectionStrategy, Component, Input } from "@angular/core";
22
import { Observable } from "rxjs";
33
import {
4-
QueryExplainerComponentData,
54
VerifyQueryDatasetBlockNotFoundError,
65
VerifyQueryDatasetNotFoundError,
76
VerifyQueryError,
@@ -10,6 +9,7 @@ import {
109
import { DatasetInfo } from "src/app/interface/navigation.interface";
1110
import { MaybeUndefined } from "src/app/common/app.types";
1211
import AppValues from "src/app/common/app.values";
12+
import { QueryExplainerComponentData } from "../../query-explainer.component";
1313

1414
@Component({
1515
selector: "app-input-data-section",
@@ -23,21 +23,6 @@ export class InputDataSectionComponent {
2323
@Input({ required: true }) inputData: QueryExplainerComponentData;
2424
public readonly DATE_FORMAT = AppValues.DISPLAY_FLOW_DATE_FORMAT;
2525

26-
public inputParamsHelper(option: string): string {
27-
switch (option) {
28-
case "SqlDataFusion":
29-
return "SQL DataFusion";
30-
case "JsonAoA":
31-
case "JsonAoa":
32-
return "JSON AoA";
33-
case "ArrowJson":
34-
return "Arrow JSON";
35-
/* istanbul ignore next */
36-
default:
37-
return "Unknown options";
38-
}
39-
}
40-
4126
public isDatasetBlockNotFoundError(error: MaybeUndefined<VerifyQueryError>, blockHash: string): boolean {
4227
return (
4328
error?.kind === VerifyQueryKindError.DatasetBlockNotFound &&

src/app/query-explainer/components/reproduced-result-section/reproduced-result-section.component.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
<div class="mt-4">
44
<app-dynamic-table
55
[hasTableHeader]="true"
6-
[schemaFields]="schemaFields(output)"
6+
[schemaFields]="schemaFields(dataJsonAoS)"
77
[idTable]="'query-explainer-table'"
8-
[dataRows]="tableSource(output)"
8+
[dataRows]="tableSource(dataJsonAoS)"
99
[attr.data-test-id]="'query-explainer-table'"
1010
/>
1111
</div>

src/app/query-explainer/components/reproduced-result-section/reproduced-result-section.component.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ describe("ReproducedResultSectionComponent", () => {
1515
});
1616
fixture = TestBed.createComponent(ReproducedResultSectionComponent);
1717
component = fixture.componentInstance;
18-
component.output = mockQueryExplainerOutput;
18+
component.dataJsonAoS = mockQueryExplainerOutput;
1919
fixture.detectChanges();
2020
});
2121

Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ChangeDetectionStrategy, Component, Input } from "@angular/core";
2-
import { QueryExplainerOutputType, QueryExplainerSchemaType } from "../../query-explainer.types";
2+
import { QueryExplainerOutputType } from "../../query-explainer.types";
33
import { extractSchemaFieldsFromData } from "src/app/common/table.helper";
44
import { DataRow, DataSchemaField } from "src/app/interface/dataset.interface";
55

@@ -9,21 +9,23 @@ import { DataRow, DataSchemaField } from "src/app/interface/dataset.interface";
99
changeDetection: ChangeDetectionStrategy.OnPush,
1010
})
1111
export class ReproducedResultSectionComponent {
12-
@Input({ required: true }) public output: QueryExplainerOutputType;
12+
@Input({ required: true }) public dataJsonAoS: QueryExplainerOutputType;
1313

1414
public tableSource(output: QueryExplainerOutputType): DataRow[] {
15-
const result = output.data.map((dataItem) => {
16-
const arr = dataItem.map((value, index) => ({ [this.columnNames(output.schema)[index]]: value }));
17-
return arr.reduce((resultObj, obj) => Object.assign(resultObj, obj), {});
18-
}) as DataRow[];
19-
return result;
20-
}
21-
22-
private columnNames(schema: QueryExplainerSchemaType): string[] {
23-
return schema.fields.map((item) => item.name);
15+
const columnNames: string[] = output.schema.fields.map((item) => item.name);
16+
return this.parseDataFromJsonAoSFormat(output.data, columnNames);
2417
}
2518

2619
public schemaFields(output: QueryExplainerOutputType): DataSchemaField[] {
2720
return extractSchemaFieldsFromData(this.tableSource(output)[0]);
2821
}
22+
23+
private parseDataFromJsonAoSFormat(data: object[], columnNames: string[]): DataRow[] {
24+
return data.map((dataItem: object) => {
25+
const arr = columnNames.map((value: string) => ({
26+
[value]: dataItem[value as keyof typeof dataItem],
27+
}));
28+
return arr.reduce((resultObj, obj) => Object.assign(resultObj, obj), {});
29+
});
30+
}
2931
}

src/app/query-explainer/components/verify-result-section/verify-result-section.component.html

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
<ng-container *ngIf="verifyResponse">
22
<div
3-
class="alert alert-info message-success mx-4 mt-4 fs-18 w-50 mx-auto d-flex align-items-center justify-content-center"
3+
class="alert alert-info message-success mx-4 mt-4 w-50 mx-auto d-flex align-items-center justify-content-center"
44
role="alert"
55
*ngIf="verifyResponse.ok"
66
>
77
<mat-icon class="me-1">check_circle</mat-icon>
8-
<span data-test-id="verification-success">Verification successful</span>
8+
<span class="fs-18" data-test-id="verification-success">Verification successful</span>
99
</div>
1010
<div
1111
*ngIf="verifyResponse.error"
@@ -14,17 +14,17 @@
1414
>
1515
<div class="d-flex align-items-center justify-content-center mb-2 fs-18">
1616
<mat-icon class="me-1">error</mat-icon>
17-
<span data-test-id="verification-failed"> Verification failed </span>
17+
<span class="fs-18" data-test-id="verification-failed"> Verification failed </span>
1818
</div>
1919

2020
<div class="fs-13 text-center" *ngIf="verifyResponse.error.message">
2121
{{ verifyResponse.error.message }}
2222
</div>
23-
<div *ngIf="isOutputMismatchError(verifyResponse.error)">
24-
<div data-test-id="error-actual-hash" class="mt-4 ms-4">
23+
<div class="mx-auto" *ngIf="isOutputMismatchError(verifyResponse.error)">
24+
<div data-test-id="error-actual-hash" class="mt-4 ms-2 fs-13">
2525
Actual hash: {{ outputMismatchError(verifyResponse.error).actual_hash }}
2626
</div>
27-
<div data-test-id="error-expected-hash" class="my-2 ms-4">
27+
<div data-test-id="error-expected-hash" class="my-2 ms-2 fs-13">
2828
Expected hash: {{ outputMismatchError(verifyResponse.error).expected_hash }}
2929
</div>
3030
</div>

src/app/query-explainer/query-explainer-routing.module.ts

-16
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,52 @@
1-
<ng-container *ngIf="componentData$ | async as componentData">
2-
<app-verify-result-section [verifyResponse]="componentData.sqlQueryVerify" />
1+
<ng-container *ngIf="commitmentUploadToken; else commitmentInputTemplate">
2+
<ng-container *ngIf="componentData$ | async as componentData">
3+
<app-verify-result-section [verifyResponse]="componentData.sqlQueryVerify" />
34

4-
<ng-container *ngIf="componentData">
5-
<div class="row">
6-
<div class="col-md-6">
7-
<app-input-data-section
8-
[blockHashObservables$]="blockHashObservables$"
9-
[datasetInfoObservables$]="datasetInfoObservables$"
10-
[inputData]="componentData"
11-
/>
5+
<ng-container *ngIf="componentData">
6+
<div class="row">
7+
<div class="col-md-6">
8+
<app-input-data-section
9+
[blockHashObservables$]="blockHashObservables$"
10+
[datasetInfoObservables$]="datasetInfoObservables$"
11+
[inputData]="componentData"
12+
/>
13+
</div>
14+
<div class="col-md-6">
15+
<app-commitment-data-section [commitmentData]="componentData" />
16+
</div>
1217
</div>
13-
<div class="col-md-6">
14-
<app-commitment-data-section [commitmentData]="componentData" />
15-
</div>
16-
</div>
1718

18-
<div class="margin-top margin-bottom" *ngIf="componentData.sqlQueryExplainerResponse.output">
19-
<app-reproduced-result-section [output]="componentData.sqlQueryExplainerResponse.output" />
20-
</div>
19+
<div class="margin-top margin-bottom" *ngIf="componentData.sqlQueryExplainerResponse.output">
20+
<app-reproduced-result-section [dataJsonAoS]="componentData.sqlQueryExplainerResponse.output" />
21+
</div>
22+
</ng-container>
2123
</ng-container>
2224
</ng-container>
25+
26+
<ng-template #commitmentInputTemplate>
27+
<div class="m-4 p-4 d-flex align-items-center flex-column justify-content-center">
28+
<div class="w-50">
29+
<div class="textarea-header p-2">Commitment</div>
30+
<div>
31+
<textarea
32+
appAutofocus
33+
rows="20"
34+
data-test-id="input-textarea"
35+
class="w-100 input-textarea p-4"
36+
[(ngModel)]="commitment"
37+
></textarea>
38+
<div class="text-end mt-3">
39+
<button
40+
[disabled]="!commitment"
41+
(click)="verifyCommitment()"
42+
class="rounded-2 verify-commitment-button px-2 py-2 btn btn-sm"
43+
type="button"
44+
data-test-id="verify-commitment-button"
45+
>
46+
Verify commitment
47+
</button>
48+
</div>
49+
</div>
50+
</div>
51+
</div>
52+
</ng-template>

0 commit comments

Comments
 (0)