Date: Fri, 30 Aug 2024 11:24:33 +0200
Subject: [PATCH 12/51] Use displayType in frontend
---
frontend/src/app/sample/sample.component.html | 2 +-
.../src/app/sample/sample.component.spec.ts | 11 +++++-----
frontend/src/app/sample/sample.component.ts | 11 ++++++----
frontend/src/app/shared/types.ts | 11 +++++-----
frontend/src/app/spindle/spindle.component.ts | 20 ++++++++++---------
5 files changed, 31 insertions(+), 24 deletions(-)
diff --git a/frontend/src/app/sample/sample.component.html b/frontend/src/app/sample/sample.component.html
index 10af818..1795692 100644
--- a/frontend/src/app/sample/sample.component.html
+++ b/frontend/src/app/sample/sample.component.html
@@ -36,7 +36,7 @@
{{ item.word }}
-
+
|
@if (showButtons(phrase.items)) {
diff --git a/frontend/src/app/sample/sample.component.spec.ts b/frontend/src/app/sample/sample.component.spec.ts
index e21d797..582593c 100644
--- a/frontend/src/app/sample/sample.component.spec.ts
+++ b/frontend/src/app/sample/sample.component.spec.ts
@@ -10,14 +10,15 @@ import {
import {
AethelDetail,
AethelDetailError,
- LexicalPhrase,
+ AethelDetailPhrase,
} from "../shared/types";
import { By } from "@angular/platform-browser";
import { ProofPipe } from "../shared/pipes/proof.pipe";
import { FontAwesomeModule } from "@fortawesome/angular-fontawesome";
-const fakePhrase: LexicalPhrase = {
+const fakePhrase: AethelDetailPhrase = {
type: "cheese->tosti",
+ displayType: "cheese -> tosti",
items: [
{
word: "cheeses",
@@ -71,7 +72,7 @@ describe("SampleComponent", () => {
it("should construct a valid route for word search", () => {
const spy = spyOn(router, "navigate");
- component.searchAethel(fakePhrase, 'word');
+ component.searchAethel(fakePhrase, "word");
expect(spy).toHaveBeenCalledOnceWith(["/aethel"], {
queryParams: { word: "cheeses" },
});
@@ -79,7 +80,7 @@ describe("SampleComponent", () => {
it("should construct a valid route for type search", () => {
const spy = spyOn(router, "navigate");
- component.searchAethel(fakePhrase, 'type');
+ component.searchAethel(fakePhrase, "type");
expect(spy).toHaveBeenCalledOnceWith(["/aethel"], {
queryParams: { type: "cheese->tosti" },
});
@@ -87,7 +88,7 @@ describe("SampleComponent", () => {
it("should construct a valid route for word and type search", () => {
const spy = spyOn(router, "navigate");
- component.searchAethel(fakePhrase, 'word-and-type');
+ component.searchAethel(fakePhrase, "word-and-type");
expect(spy).toHaveBeenCalledOnceWith(["/aethel"], {
queryParams: { word: "cheeses", type: "cheese->tosti" },
});
diff --git a/frontend/src/app/sample/sample.component.ts b/frontend/src/app/sample/sample.component.ts
index 7330533..bbefff1 100644
--- a/frontend/src/app/sample/sample.component.ts
+++ b/frontend/src/app/sample/sample.component.ts
@@ -2,7 +2,7 @@ import { Component } from "@angular/core";
import { ActivatedRoute, Params, Router } from "@angular/router";
import { AethelApiService } from "../shared/services/aethel-api.service";
import { map } from "rxjs";
-import { AethelMode, LexicalPhrase } from "../shared/types";
+import { AethelMode, AethelDetailPhrase } from "../shared/types";
import { isNonNull } from "../shared/operators/IsNonNull";
import { faArrowLeft } from "@fortawesome/free-solid-svg-icons";
import { Location } from "@angular/common";
@@ -31,12 +31,12 @@ export class SampleComponent {
private location: Location,
) {}
- public searchAethel(phrase: LexicalPhrase, mode: AethelMode): void {
+ public searchAethel(phrase: AethelDetailPhrase, mode: AethelMode): void {
const queryParams = this.formatQueryParams(phrase, mode);
this.router.navigate(["/aethel"], { queryParams });
}
- public showButtons(items: LexicalPhrase["items"]): boolean {
+ public showButtons(items: AethelDetailPhrase["items"]): boolean {
// Buttons are hidden if the phrase contains too few characters.
const combined = items.map((item) => item.word).join(" ");
return combined.length > 2;
@@ -46,7 +46,10 @@ export class SampleComponent {
this.location.back();
}
- private formatQueryParams(phrase: LexicalPhrase, mode: AethelMode): Params {
+ private formatQueryParams(
+ phrase: AethelDetailPhrase,
+ mode: AethelMode,
+ ): Params {
const queryParams: Params = {};
if (mode === "word" || mode === "word-and-type") {
queryParams["word"] = phrase.items
diff --git a/frontend/src/app/shared/types.ts b/frontend/src/app/shared/types.ts
index c547915..cb21ee4 100644
--- a/frontend/src/app/shared/types.ts
+++ b/frontend/src/app/shared/types.ts
@@ -20,9 +20,10 @@ type LexicalItem = {
lemma: string;
};
-export type LexicalPhrase = {
+export type AethelDetailPhrase = {
items: LexicalItem[];
type: string;
+ displayType: string;
};
// Should correspond with SpindleResponse dataclass in backend.
@@ -32,7 +33,7 @@ export interface SpindleReturn {
pdf: string | null;
redirect: string | null;
term: string | null;
- lexical_phrases: LexicalPhrase[];
+ lexical_phrases: AethelDetailPhrase[];
proof: Record | null;
}
@@ -49,11 +50,11 @@ export interface AethelListLexicalItem {
}
export interface AethelListPhrase {
- items: AethelListLexicalItem[]
+ items: AethelListLexicalItem[];
}
export interface AethelListResult {
- phrase: AethelListPhrase
+ phrase: AethelListPhrase;
type: string;
displayType: string;
sampleCount: number;
@@ -76,7 +77,7 @@ export interface AethelDetailResult {
name: string;
term: string;
subset: string;
- phrases: LexicalPhrase[];
+ phrases: AethelDetailPhrase[];
}
export interface AethelDetail {
diff --git a/frontend/src/app/spindle/spindle.component.ts b/frontend/src/app/spindle/spindle.component.ts
index d9366a4..855abba 100644
--- a/frontend/src/app/spindle/spindle.component.ts
+++ b/frontend/src/app/spindle/spindle.component.ts
@@ -5,7 +5,7 @@ import { ErrorHandlerService } from "../shared/services/error-handler.service";
import { AlertService } from "../shared/services/alert.service";
import { AlertType } from "../shared/components/alert/alert.component";
import { faDownload, faCopy } from "@fortawesome/free-solid-svg-icons";
-import { LexicalPhrase, SpindleMode } from "../shared/types";
+import { AethelDetailPhrase, SpindleMode } from "../shared/types";
import { SpindleApiService } from "../shared/services/spindle-api.service";
import { Subject, filter, map, share, switchMap, takeUntil, timer } from "rxjs";
import { StatusService } from "../shared/services/status.service";
@@ -26,7 +26,7 @@ export class SpindleComponent implements OnInit {
});
term: string | null = null;
textOutput: TextOutput | null = null;
- lexicalPhrases: LexicalPhrase[] = [];
+ lexicalPhrases: AethelDetailPhrase[] = [];
loading$ = this.apiService.loading$;
faCopy = faCopy;
@@ -37,8 +37,8 @@ export class SpindleComponent implements OnInit {
spindleReady$ = timer(0, 5000).pipe(
takeUntil(this.stopStatus$),
switchMap(() => this.statusService.get()),
- map(status => status.spindle),
- share()
+ map((status) => status.spindle),
+ share(),
);
constructor(
@@ -46,14 +46,16 @@ export class SpindleComponent implements OnInit {
private alertService: AlertService,
private errorHandler: ErrorHandlerService,
private destroyRef: DestroyRef,
- private statusService: StatusService
+ private statusService: StatusService,
) {}
ngOnInit(): void {
- this.spindleReady$.pipe(
- filter(ready => ready === true),
- takeUntilDestroyed(this.destroyRef)
- ).subscribe(() => this.stopStatus$.next());
+ this.spindleReady$
+ .pipe(
+ filter((ready) => ready === true),
+ takeUntilDestroyed(this.destroyRef),
+ )
+ .subscribe(() => this.stopStatus$.next());
this.apiService.output$
.pipe(takeUntilDestroyed(this.destroyRef))
From cd720145f8dc702e7c74147a723a8afff4e8819f Mon Sep 17 00:00:00 2001
From: Xander Vertegaal
Date: Fri, 30 Aug 2024 11:49:20 +0200
Subject: [PATCH 13/51] Rename serialize_phrases
---
backend/aethel_db/views/detail.py | 4 ++--
backend/spindle/utils.py | 4 ++--
backend/spindle/views.py | 9 ++++-----
3 files changed, 8 insertions(+), 9 deletions(-)
diff --git a/backend/aethel_db/views/detail.py b/backend/aethel_db/views/detail.py
index b857b64..49f917e 100644
--- a/backend/aethel_db/views/detail.py
+++ b/backend/aethel_db/views/detail.py
@@ -4,7 +4,7 @@
from django.http import HttpRequest, JsonResponse
from rest_framework import status
from rest_framework.views import APIView
-from spindle.utils import serialize_phrases_with_infix_notation
+from spindle.utils import serialize_phrases
from aethel.frontend import Sample
from aethel_db.models import dataset
@@ -59,7 +59,7 @@ def parse_sample(self, sample: Sample) -> None:
name=sample.name,
term=str(sample.proof.term),
subset=sample.subset,
- phrases=serialize_phrases_with_infix_notation(sample.lexical_phrases),
+ phrases=serialize_phrases(sample.lexical_phrases),
)
def json_response(self) -> JsonResponse:
diff --git a/backend/spindle/utils.py b/backend/spindle/utils.py
index f5793a9..159fe68 100644
--- a/backend/spindle/utils.py
+++ b/backend/spindle/utils.py
@@ -2,13 +2,13 @@
from aethel.mill.types import type_prefix, type_repr
-def serialize_phrases_with_infix_notation(
+def serialize_phrases(
lexical_phrases: list[LexicalPhrase],
) -> list[dict[str, str]]:
"""
Serializes a list of LexicalPhrases in a human-readable infix notation that is already available in Æthel in Type.__repr__ or type_repr(). This is used to display the types in the frontend.
- The standard JSON serialization of phrases uses a prefix notation for types, which is good for data-exchange purposes (easier parsing) but less ideal for human consumption. This notation will be used to query.
+ The standard JSON serialization of phrases uses a prefix notation for types, which is good for data-exchange purposes (easier parsing) but less ideal for human consumption. This notation is used to query.
"""
return [
dict(
diff --git a/backend/spindle/views.py b/backend/spindle/views.py
index 5581dfe..635a05f 100644
--- a/backend/spindle/views.py
+++ b/backend/spindle/views.py
@@ -22,7 +22,7 @@
serial_proof_to_json,
)
-from spindle.utils import serialize_phrases_with_infix_notation
+from spindle.utils import serialize_phrases
http = urllib3.PoolManager()
@@ -31,7 +31,6 @@
Mode = Literal["latex", "pdf", "overleaf", "term-table", "proof"]
-
class SpindleErrorSource(Enum):
INPUT = "input"
SPINDLE = "spindle"
@@ -193,7 +192,7 @@ def overleaf_redirect(self, latex: str) -> JsonResponse:
def term_table_response(self, parsed: ParserResponse) -> JsonResponse:
"""Return the term and the lexical phrases as a JSON response."""
- phrases = serialize_phrases_with_infix_notation(parsed.lexical_phrases)
+ phrases = serialize_phrases(parsed.lexical_phrases)
return SpindleResponse(
term=str(parsed.proof.term),
lexical_phrases=phrases,
@@ -210,10 +209,10 @@ def spindle_status():
try:
r = http.request(
method="GET",
- url=settings.SPINDLE_URL + '/status/',
+ url=settings.SPINDLE_URL + "/status/",
headers={"Content-Type": "application/json"},
timeout=1,
- retries=False
+ retries=False,
)
return r.status < 400
except Exception:
From 35dd308e463283671040103507d95056b6893813 Mon Sep 17 00:00:00 2001
From: Xander Vertegaal
Date: Fri, 30 Aug 2024 11:49:37 +0200
Subject: [PATCH 14/51] Camelize displayType for Spindle
---
backend/spindle/views.py | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/backend/spindle/views.py b/backend/spindle/views.py
index 635a05f..89452f6 100644
--- a/backend/spindle/views.py
+++ b/backend/spindle/views.py
@@ -51,6 +51,16 @@ class SpindleResponse:
def json_response(self) -> JsonResponse:
# TODO: set HTTP error code when error is not None
+
+ # Convert display_type to displayType for frontend.
+ camelized = [
+ {
+ **{k: v for k, v in phrase.items() if k != "display_type"},
+ "displayType": phrase["display_type"],
+ }
+ for phrase in self.lexical_phrases
+ ]
+
return JsonResponse(
{
"latex": self.latex,
@@ -58,7 +68,7 @@ def json_response(self) -> JsonResponse:
"redirect": self.redirect,
"error": self.error.value if self.error else None,
"term": self.term,
- "lexical_phrases": self.lexical_phrases,
+ "lexical_phrases": camelized,
"proof": self.proof,
}
)
From aa9dec9411655e899cffa1e8209464d598d09b62 Mon Sep 17 00:00:00 2001
From: Xander Vertegaal
Date: Fri, 30 Aug 2024 11:49:52 +0200
Subject: [PATCH 15/51] Use displayType in Spindle frontend
---
frontend/src/app/spindle/spindle.component.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frontend/src/app/spindle/spindle.component.html b/frontend/src/app/spindle/spindle.component.html
index 39ffc61..2ab044e 100644
--- a/frontend/src/app/spindle/spindle.component.html
+++ b/frontend/src/app/spindle/spindle.component.html
@@ -73,7 +73,7 @@ Term:
{{ item.word }}
|
- |
+ |
From ac98dcb2a1abbb9ae1d92c5b691815d21a3a453b Mon Sep 17 00:00:00 2001
From: Xander Vertegaal
Date: Fri, 30 Aug 2024 12:08:32 +0200
Subject: [PATCH 16/51] Tidying
---
backend/aethel_db/views/detail.py | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/backend/aethel_db/views/detail.py b/backend/aethel_db/views/detail.py
index 49f917e..3744ed8 100644
--- a/backend/aethel_db/views/detail.py
+++ b/backend/aethel_db/views/detail.py
@@ -67,11 +67,9 @@ def json_response(self) -> JsonResponse:
AETHEL_DETAIL_STATUS_CODES[self.error] if self.error else status.HTTP_200_OK
)
- result_data = self.result.serialize() if self.result else None
-
return JsonResponse(
{
- "result": result_data if self.result else None,
+ "result": self.result.serialize() if self.result else None,
"error": self.error,
},
status=status_code,
From 6091c22707c7da51170a1aff3ada88c4194ad2e2 Mon Sep 17 00:00:00 2001
From: Xander Vertegaal
Date: Fri, 30 Aug 2024 12:17:04 +0200
Subject: [PATCH 17/51] Fix button styling
---
.../spindle/export-button/export-button.component.html | 2 +-
.../spindle/export-button/export-button.component.scss | 10 +++++-----
.../spindle/export-button/export-button.component.ts | 4 ++++
3 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/frontend/src/app/spindle/export-button/export-button.component.html b/frontend/src/app/spindle/export-button/export-button.component.html
index 62c3289..f758eaf 100644
--- a/frontend/src/app/spindle/export-button/export-button.component.html
+++ b/frontend/src/app/spindle/export-button/export-button.component.html
@@ -1,5 +1,5 @@
|