Skip to content

Commit 20ca2e4

Browse files
Piv94165alice.juanperiercCharles Periereric-nguyen-cs
authored
feat(frontend): enable advanced research (#463)
* working on component querying backend * feat(frontend): link advanced research component with backend * feat(frontend): add parent, child, ancestor, descendant filter * feat(frontend): disable modified filter with comment * feat(frontend): add search results with pagination * feat(frontend): search expression is refactored by backend * refactor(frontend): replace search page, avoid useeffect and many rerenders * refactor(frontend): a file for each main component * feat(frontend): is:external and is:not:external filter * feat(frontend): add external filter * refactor(frontend): clean code, add error message if needed * lint * refactor(frontend): change multiple select filter behaviour * refactor(frontend): remove useless states and props * feat(frontend): unify design with select and inputs components only * refactor(frontend): refactor singleSelectFilter * feat: improve search results display (#484) * feat(frontend): make language selection for translations more intuitive (#461) The PR modifies the translations section of the edit entry page: * Changes "All languages" terminology to "Fallback translations" (fixes #458) * Adds an info alert if "en" (English) or "xx" (Fallback translations) is not the main language for an entry (fixes #457) / Fixes the fact that the alert message about changing the display name of a language appears even if the language had no translations and we add the first one (fixes #459) * Adds a "Show all existing translations" checkbox to see all the languages that currently have translations, with their translations Adds a possibility to "pin" languages to select them (so they stay in local storage and appear at the top for each entry), and a possibility to hide (unselect) these languages easily (with an icon next to their title) * Modifies the selection of new languages: I removed the "number of languages shown" button that had to be clicked to add a language, and created a "Show another language" button at the bottom of the section. Also, the dialog is now an autocomplete instead of a select, and you just type the languages that you want to add and see languages that are not selected, instead of seeing all current languages and being able to remove them. The autocomplete with the options is also automatically focused when opening the dialog. * Adds vite-plugin-svgr to easily import svg files in React --------- Co-authored-by: Charles Perier <[email protected]> * feat: add property filter to search API (#456) * feat: add property filter to search API * chore: generate SDK * chore: Add info banners on the frontend (#473) * docs: add info banners * refactor: delete unnecessary components * fix: add line break * improve search results, and few other improvements * show translations instead of translated languages --------- Co-authored-by: Charles Perier <[email protected]> Co-authored-by: Eric Nguyen <[email protected]> * refactor(frontend): remove useless lines, add css * rewording * test --------- Co-authored-by: alice.juan <[email protected]> Co-authored-by: Charles Perier <[email protected]> Co-authored-by: Charles Perier <[email protected]> Co-authored-by: Eric Nguyen <[email protected]>
1 parent 6391abb commit 20ca2e4

15 files changed

+768
-511
lines changed

backend/editor/models/node_models.py

-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ class EntryNodeCreate(BaseModel):
3030
class EntryNode(BaseModel):
3131
id: str
3232
preceding_lines: list[str]
33-
src_position: int
3433
main_language: str
3534
tags: dict[str, list[str]]
3635
properties: dict[str, str]

taxonomy-editor-frontend/src/App.tsx

+3-4
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,11 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
77

88
import { createTheme, CssBaseline, ThemeProvider } from "@mui/material";
99

10-
import { RootNodesWrapper } from "./pages/project/root-nodes";
1110
import { EditEntryWrapper } from "./pages/project/editentry";
1211
import { ExportTaxonomyWrapper } from "./pages/project/export";
1312
import { GoToProject } from "./pages/go-to-project";
1413
import { Home } from "./pages/home";
15-
import { SearchNodeWrapper } from "./pages/project/search";
14+
import { AdvancedSearchForm } from "./pages/project/search";
1615
import { StartProject } from "./pages/startproject";
1716
import { Errors } from "./pages/project/errors";
1817
import { ProjectPage, projectLoader } from "./pages/project";
@@ -58,15 +57,15 @@ const router = createBrowserRouter([
5857
},
5958
{
6059
path: "entry",
61-
element: <RootNodesWrapper />,
60+
element: <Navigate to="../search" relative="path" />,
6261
},
6362
{
6463
path: "entry/:id",
6564
element: <EditEntryWrapper />,
6665
},
6766
{
6867
path: "search",
69-
element: <SearchNodeWrapper />,
68+
element: <AdvancedSearchForm />,
7069
},
7170
{
7271
path: "errors",
Original file line numberDiff line numberDiff line change
@@ -1,8 +1 @@
1-
export type NodeInfo = {
2-
id: string;
3-
is_external: boolean;
4-
};
5-
6-
export type RootEntriesAPIResponse = Array<NodeInfo[]>;
7-
81
export type ParentsAPIResponse = string[];
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import { EntryNode } from "@/client";
2+
import {
3+
Chip,
4+
Stack,
5+
TableBody,
6+
TableCell,
7+
TableRow,
8+
Tooltip,
9+
Typography,
10+
} from "@mui/material";
11+
import { Link } from "react-router-dom";
12+
import ISO6391 from "iso-639-1";
13+
import { useEffect, useState } from "react";
14+
import { SHOWN_LANGUAGES_KEY } from "@/pages/project/editentry/ListTranslations";
15+
16+
type Props = {
17+
entryNodes: EntryNode[];
18+
taxonomyName: string;
19+
branchName: string;
20+
};
21+
22+
const EntryTitle = ({ id }: { id: string }) => {
23+
const languageCode = id.split(":", 1)[0];
24+
const languageName = ISO6391.getName(languageCode);
25+
return (
26+
<Typography variant="subtitle1">
27+
{id.slice(languageCode.length + 1)}
28+
<Tooltip title="Main language of the entry" placement="right" arrow>
29+
<Chip label={languageName} size="small" sx={{ ml: 1, mb: 0.5 }} />
30+
</Tooltip>
31+
</Typography>
32+
);
33+
};
34+
35+
const getTranslations = (
36+
tags: Record<string, string[]>,
37+
shownLanguageCodes: string[]
38+
) => {
39+
const result: string[] = [];
40+
41+
shownLanguageCodes.forEach((languageCode) => {
42+
const languageName =
43+
languageCode === "xx"
44+
? "Fallback translations"
45+
: ISO6391.getName(languageCode);
46+
const translations = tags[`tags_${languageCode}`];
47+
if (translations) {
48+
result.push(`${languageName}: ${translations.join(", ")}`);
49+
}
50+
});
51+
52+
return result;
53+
};
54+
55+
export const EntryNodesTableBody = ({
56+
entryNodes,
57+
taxonomyName,
58+
branchName,
59+
}: Props) => {
60+
const [shownLanguageCodes, setShownLanguageCodes] = useState<string[]>([]);
61+
62+
useEffect(() => {
63+
// get shown languages from local storage if it exists else use main language
64+
try {
65+
const rawLocalStorageShownLanguages =
66+
localStorage.getItem(SHOWN_LANGUAGES_KEY);
67+
let localStorageShownLanguages: string[] | null =
68+
rawLocalStorageShownLanguages
69+
? JSON.parse(rawLocalStorageShownLanguages)
70+
: null;
71+
// validate that shown languages is an array of strings and filter all items that are valid language codes
72+
if (
73+
Array.isArray(localStorageShownLanguages) &&
74+
localStorageShownLanguages.every((item) => typeof item === "string")
75+
) {
76+
localStorageShownLanguages = localStorageShownLanguages.filter(
77+
(item) => {
78+
return item === "xx" || ISO6391.validate(item);
79+
}
80+
);
81+
} else {
82+
localStorageShownLanguages = [];
83+
}
84+
setShownLanguageCodes(localStorageShownLanguages);
85+
} catch (e) {
86+
// shown languages is an empty list, when we can't parse the local storage
87+
console.log(e);
88+
}
89+
}, []);
90+
91+
return (
92+
<>
93+
<TableBody>
94+
{entryNodes.map(({ id, isExternal, tags }) => (
95+
<TableRow
96+
key={id}
97+
hover
98+
component={Link}
99+
to={`/${taxonomyName}/${branchName}/entry/${id}`}
100+
sx={{ textDecoration: "none" }}
101+
>
102+
<TableCell align="left" component="td" scope="row">
103+
<Stack gap={0.5}>
104+
<EntryTitle id={id} />
105+
{isExternal && (
106+
<Typography variant="subtitle2" color="secondary">
107+
External Node
108+
</Typography>
109+
)}
110+
{getTranslations(tags, shownLanguageCodes).map((line, i) => (
111+
<Typography key={i} variant="body2" color="inherit">
112+
{line}
113+
</Typography>
114+
))}
115+
</Stack>
116+
</TableCell>
117+
</TableRow>
118+
))}
119+
</TableBody>
120+
</>
121+
);
122+
};

taxonomy-editor-frontend/src/components/NodesTableBody.tsx

-48
This file was deleted.

taxonomy-editor-frontend/src/components/ResponsiveAppBar.tsx

+1-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ const getDisplayedPages = (
2626

2727
const navUrlPrefix = `${params.taxonomyName}/${params.branchName}/`;
2828
return [
29-
{ url: navUrlPrefix + "entry", translationKey: "Nodes" },
3029
{ url: navUrlPrefix + "search", translationKey: "Search" },
3130
{ url: navUrlPrefix + "export", translationKey: "Export" },
3231
{ url: navUrlPrefix + "errors", translationKey: "Errors" },
@@ -46,7 +45,7 @@ export const ResponsiveAppBar = () => {
4645
};
4746

4847
return (
49-
<AppBar position="sticky" sx={{ textColor: "#000", background: "#f2e9e4" }}>
48+
<AppBar position="sticky" sx={{ color: "#000", background: "#f2e9e4" }}>
5049
<Container maxWidth={false}>
5150
<Toolbar disableGutters>
5251
{/* Mobile content */}

taxonomy-editor-frontend/src/pages/project/editentry/ListTranslations.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { useMemo, useEffect, useState } from "react";
1616
import ISO6391 from "iso-639-1";
1717
import { TranslationTags } from "./TranslationTags";
1818

19-
const SHOWN_LANGUAGES_KEY = "shownLanguages";
19+
export const SHOWN_LANGUAGES_KEY = "shownLanguages";
2020

2121
const getLanguageName = (languageCode: string): string => {
2222
if (languageCode === "xx") {

0 commit comments

Comments
 (0)