Skip to content

Commit 53cee3a

Browse files
committed
Refactor and enhance SN site locale management
Refactored backend API to use 'snSiteId' instead of 'ignoredSnSiteId' and improved locale association logic. In the React app, split multi-language list and form pages, added SNSiteLocaleForm component, updated routes for locale CRUD, and improved the SN site locale service for clearer API usage. Also renamed SN site fields page for consistency.
1 parent 6f0617e commit 53cee3a

File tree

7 files changed

+238
-59
lines changed

7 files changed

+238
-59
lines changed

turing-app/src/main/java/com/viglet/turing/api/sn/console/TurSNSiteLocaleAPI.java

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
*/
5151

5252
@RestController
53-
@RequestMapping("/api/sn/{ignoredSnSiteId}/locale")
53+
@RequestMapping("/api/sn/{snSiteId}/locale")
5454
@Tag(name = "Semantic Navigation Locale", description = "Semantic Navigation Locale API")
5555
public class TurSNSiteLocaleAPI {
5656
private static final Locale DEFAULT_LANGUAGE = Locale.US;
@@ -68,15 +68,15 @@ public TurSNSiteLocaleAPI(TurSNSiteRepository turSNSiteRepository,
6868

6969
@Operation(summary = "Semantic Navigation Site Locale List")
7070
@GetMapping
71-
public List<TurSNSiteLocale> turSNSiteLocaleList(@PathVariable String ignoredSnSiteId) {
72-
return turSNSiteRepository.findById(ignoredSnSiteId).map(site -> this.turSNSiteLocaleRepository
71+
public List<TurSNSiteLocale> turSNSiteLocaleList(@PathVariable String snSiteId) {
72+
return turSNSiteRepository.findById(snSiteId).map(site -> this.turSNSiteLocaleRepository
7373
.findByTurSNSite(Sort.by(Sort.Order.asc("language").ignoreCase()), site))
7474
.orElse(Collections.emptyList());
7575
}
7676

7777
@Operation(summary = "Show a Semantic Navigation Site Locale")
7878
@GetMapping("/{id}")
79-
public TurSNSiteLocale turSNSiteFieldExtGet(@PathVariable String ignoredSnSiteId, @PathVariable String id) {
79+
public TurSNSiteLocale turSNSiteFieldExtGet(@PathVariable String snSiteId, @PathVariable String id) {
8080
return turSNSiteLocaleRepository.findById(id).orElse(new TurSNSiteLocale());
8181
}
8282

@@ -99,25 +99,29 @@ public TurSNSiteLocale turSNSiteLocaleUpdate(@PathVariable String id,
9999
@Transactional
100100
@Operation(summary = "Delete a Semantic Navigation Site Locale")
101101
@DeleteMapping("/{id}")
102-
public boolean turSNSiteLocaleDelete(@PathVariable String id, @PathVariable String ignoredSnSiteId) {
103-
turSNSiteLocaleRepository.deleteById(id);
104-
return true;
102+
public boolean turSNSiteLocaleDelete(@PathVariable String id, @PathVariable String snSiteId) {
103+
return turSNSiteRepository.findById(snSiteId).map(turSNSite -> {
104+
turSNSiteLocaleRepository.deleteById(id);
105+
return true;
106+
}).orElse(false);
105107
}
106108

107109
@Operation(summary = "Create a Semantic Navigation Site Locale")
108110
@PostMapping
109111
public TurSNSiteLocale turSNSiteLocaleAdd(@RequestBody TurSNSiteLocale turSNSiteLocale, Principal principal,
110-
@PathVariable String ignoredSnSiteId) {
111-
turSNSiteLocale.setCore(turSNTemplate.createSolrCore(turSNSiteLocale, principal.getName()));
112-
turSNSiteLocaleRepository.save(turSNSiteLocale);
113-
114-
return turSNSiteLocale;
112+
@PathVariable String snSiteId) {
113+
return turSNSiteRepository.findById(snSiteId).map(turSNSite -> {
114+
turSNSiteLocale.setTurSNSite(turSNSite);
115+
turSNSiteLocale.setCore(turSNTemplate.createSolrCore(turSNSiteLocale, principal.getName()));
116+
turSNSiteLocaleRepository.save(turSNSiteLocale);
117+
return turSNSiteLocale;
118+
}).orElse(new TurSNSiteLocale());
115119
}
116120

117121
@Operation(summary = "Semantic Navigation Site Locale structure")
118122
@GetMapping("structure")
119-
public TurSNSiteLocale turSNSiteLocaleStructure(@PathVariable String ignoredSnSiteId) {
120-
return turSNSiteRepository.findById(ignoredSnSiteId).map(turSNSite -> {
123+
public TurSNSiteLocale turSNSiteLocaleStructure(@PathVariable String snSiteId) {
124+
return turSNSiteRepository.findById(snSiteId).map(turSNSite -> {
121125
TurSNSiteLocale turSNSiteLocale = new TurSNSiteLocale();
122126
turSNSiteLocale.setLanguage(DEFAULT_LANGUAGE);
123127
turSNSiteLocale.setTurSNSite(turSNSite);

turing-react/src/app/console/sn/sn.site.fields.page.tsx renamed to turing-react/src/app/console/sn/sn.site.field.list.page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ export const columns: ColumnDef<TurSNSiteField>[] = [
138138
},
139139
]
140140
const turSNFieldService = new TurSNFieldService();
141-
export default function SNSiteFieldsPage() {
141+
export default function SNSiteFieldListPage() {
142142
const { id } = useParams() as { id: string };
143143
const [data, setSnField] = React.useState<TurSNSiteField[]>([]);
144144
const [sorting, setSorting] = React.useState<SortingState>([])
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { ROUTES } from "@/app/routes.const";
2+
import { BlankSlate } from "@/components/blank-slate.tsx";
3+
import { SNSiteMultiLanguageDataTable } from "@/components/sn/locales/sn.site.locale.data.table.tsx";
4+
import { SubPageHeader } from "@/components/sub.page.header";
5+
import type { TurSNSiteLocale } from "@/models/sn/sn-site-locale.model.ts";
6+
import { TurSNSiteLocaleService } from "@/services/sn/sn.site.locale.service";
7+
import { IconLanguage } from "@tabler/icons-react";
8+
import * as React from "react";
9+
import { useParams } from "react-router-dom";
10+
11+
const turSNSiteLocaleService = new TurSNSiteLocaleService();
12+
export default function SNSiteMultiLanguageListPage() {
13+
const { id } = useParams() as { id: string };
14+
const [data, setData] = React.useState<TurSNSiteLocale[]>({} as TurSNSiteLocale[]);
15+
React.useEffect(() => {
16+
turSNSiteLocaleService.query(id).then(setData);
17+
}, [id])
18+
19+
return (
20+
<>
21+
{data.length > 0 ? (
22+
<>
23+
<SubPageHeader icon={IconLanguage} title="Multi Language" description="Define Multi Languages."
24+
urlNew={`${ROUTES.SN_INSTANCE}/${id}/locale/new`} />
25+
<SNSiteMultiLanguageDataTable data={data} />
26+
</>
27+
) : (
28+
< BlankSlate
29+
icon={IconLanguage}
30+
title="You don't seem to have any language."
31+
description="Create a new language to semantic navigation search works."
32+
buttonText="New language"
33+
urlNew={`${ROUTES.SN_INSTANCE}/${id}/locale/new`}
34+
/>
35+
)}
36+
</>
37+
)
38+
}
Lines changed: 20 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,28 @@
1-
import { ROUTES } from "@/app/routes.const";
2-
import { BlankSlate } from "@/components/blank-slate.tsx";
3-
import { SNSiteMultiLanguageDataTable } from "@/components/sn/locales/sn.site.locale.data.table.tsx";
1+
import { SNSiteLocaleForm } from "@/components/sn/locales/sn.site.locale.form";
42
import { SubPageHeader } from "@/components/sub.page.header";
5-
import type { TurSNSiteLocale } from "@/models/sn/sn-site-locale.model.ts";
3+
import type { TurSNSiteLocale } from "@/models/sn/sn-site-locale.model";
64
import { TurSNSiteLocaleService } from "@/services/sn/sn.site.locale.service";
75
import { IconLanguage } from "@tabler/icons-react";
8-
import * as React from "react";
6+
import { useEffect, useState } from "react";
97
import { useParams } from "react-router-dom";
108

119
const turSNSiteLocaleService = new TurSNSiteLocaleService();
12-
export default function SNSiteMultiLanguagePage() {
13-
const { id } = useParams() as { id: string };
14-
const [data, setData] = React.useState<TurSNSiteLocale[]>({} as TurSNSiteLocale[]);
15-
React.useEffect(() => {
16-
turSNSiteLocaleService.query(id).then(setData);
17-
}, [id])
1810

19-
return (
20-
<>
21-
{data.length > 0 ? (
22-
<>
23-
<SubPageHeader icon={IconLanguage} title="Multi Language" description="Define Multi Languages."
24-
urlNew={"/sn/site/" + id + "/locale/new"} />
25-
<SNSiteMultiLanguageDataTable data={data} />
26-
</>
27-
) : (
28-
< BlankSlate
29-
icon={IconLanguage}
30-
title="You don't seem to have any language."
31-
description="Create a new language to semantic navigation search works."
32-
buttonText="New language"
33-
urlNew={`${ROUTES.SN_INSTANCE}/${id}/locale/new`}
34-
/>
35-
)}
36-
</>
37-
)
11+
export default function SNSiteMultiLanguagePage() {
12+
const { id, localeId } = useParams() as { id: string, localeId: string };
13+
const [snLocale, setSnLocale] = useState<TurSNSiteLocale>({} as TurSNSiteLocale);
14+
const [isNew, setIsNew] = useState<boolean>(true);
15+
useEffect(() => {
16+
if (localeId !== "new") {
17+
turSNSiteLocaleService.get(id, localeId).then(setSnLocale);
18+
setIsNew(false);
19+
}
20+
}, [id, localeId])
21+
return (
22+
<>
23+
{isNew && <SubPageHeader icon={IconLanguage} title="Multi Language" description="Define Multi Languages." />}
24+
{!isNew && <SubPageHeader icon={IconLanguage} title={snLocale.language} description={snLocale.core} />}
25+
<SNSiteLocaleForm snSiteId={id} snLocale={snLocale} isNew={isNew} />
26+
</>
27+
)
3828
}

turing-react/src/app/routes/sn.routes.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@ import { Navigate, Route, useParams } from "react-router-dom"
22
import SNSiteBehaviorPage from "../console/sn/sn.site.behavior.page"
33
import SNSiteDetailPage from "../console/sn/sn.site.detail.page"
44
import SNSiteFacetOrderingPage from "../console/sn/sn.site.facets.ordering.page"
5+
import SNSiteFieldListPage from "../console/sn/sn.site.field.list.page"
56
import SNSiteFieldPage from "../console/sn/sn.site.field.page"
6-
import SNSiteFieldsPage from "../console/sn/sn.site.fields.page"
77
import SNSiteGenAIPage from "../console/sn/sn.site.genai.page"
88
import SNSiteListPage from "../console/sn/sn.site.list.page"
99
import SNSiteMergeProvidersListPage from "../console/sn/sn.site.merge.providers.list.page"
1010
import SNSiteMergeProvidersPage from "../console/sn/sn.site.merge.providers.page"
11+
import SNSiteMultiLanguageListPage from "../console/sn/sn.site.multi.language.list.page"
1112
import SNSiteMultiLanguagePage from "../console/sn/sn.site.multi.language.page"
1213
import SNSitePage from "../console/sn/sn.site.page"
1314
import SNSiteResultRankingListPage from "../console/sn/sn.site.result.ranking.list.page"
@@ -30,19 +31,20 @@ export const SNRoutes = (
3031
<Route path={`${ROUTES.SN_INSTANCE}/:id`} element={<SNSitePage />}>
3132
<Route index element={<RedirectToSNDetail />} />
3233
<Route path={'detail'} element={<SNSiteDetailPage />} />
33-
<Route path={'locale'} element={<SNSiteMultiLanguagePage />} />
34-
<Route path={'field'} element={<SNSiteFieldsPage />} />
34+
<Route path={'locale'} element={<SNSiteMultiLanguageListPage />} />
35+
<Route path={'locale/:localeId'} element={<SNSiteMultiLanguagePage />} />
36+
<Route path={'field'} element={<SNSiteFieldListPage />} />
37+
<Route path={'field/:fieldId'} element={<SNSiteFieldPage />} />
3538
<Route path={'behavior'} element={<SNSiteBehaviorPage />} />
3639
<Route path={'facet-ordering'} element={<SNSiteFacetOrderingPage />} />
3740
<Route path={'ai'} element={<SNSiteGenAIPage />} />
3841
<Route path={'result-ranking'} element={<SNSiteResultRankingListPage />} />
3942
<Route path={'merge-providers'} element={<SNSiteMergeProvidersListPage />} />
4043
<Route path={'spotlight'} element={<SNSiteSpotlightListPage />} />
44+
<Route path={'spotlight/:spotlightId'} element={<SNSiteSpotlightPage />} />
4145
<Route path={'top-terms'} element={<SNSiteTopSearchTermsPage />} />
42-
<Route path={'field/:fieldId'} element={<SNSiteFieldPage />} />
4346
<Route path={'result-ranking/:resultRankingId'} element={<SNSiteResultRankingPage />} />
4447
<Route path={'merge-providers/:mergeProviderId'} element={<SNSiteMergeProvidersPage />} />
45-
<Route path={'spotlight/:spotlightId'} element={<SNSiteSpotlightPage />} />
4648
</Route>
4749
</Route>
4850
)
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
"use client"
2+
import {
3+
Button
4+
} from "@/components/ui/button"
5+
import {
6+
Form,
7+
FormControl,
8+
FormDescription,
9+
FormField,
10+
FormItem,
11+
FormLabel,
12+
FormMessage,
13+
} from "@/components/ui/form"
14+
import {
15+
Input
16+
} from "@/components/ui/input"
17+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
18+
import type { TurLocale } from "@/models/locale/locale.model"
19+
import type { TurSNSiteLocale } from "@/models/sn/sn-site-locale.model"
20+
import { TurLocaleService } from "@/services/locale/locale.service"
21+
import { TurSNSiteLocaleService } from "@/services/sn/sn.site.locale.service"
22+
import { useEffect, useState } from "react"
23+
import {
24+
useForm
25+
} from "react-hook-form"
26+
import { useNavigate } from "react-router-dom"
27+
import { toast } from "sonner"
28+
29+
30+
interface Props {
31+
snSiteId: string;
32+
snLocale: TurSNSiteLocale;
33+
isNew: boolean;
34+
}
35+
const turSNSiteLocaleService = new TurSNSiteLocaleService();
36+
37+
export const SNSiteLocaleForm: React.FC<Props> = ({ snSiteId, snLocale, isNew }) => {
38+
const [locales, setLocales] = useState<TurLocale[]>([]);
39+
const form = useForm<TurSNSiteLocale>({
40+
defaultValues: snLocale
41+
});
42+
const urlBase = `/admin/sn/instance/${snSiteId}/locale`;
43+
const navigate = useNavigate()
44+
45+
useEffect(() => {
46+
form.reset(snLocale);
47+
}, [form, snLocale]);
48+
49+
useEffect(() => {
50+
const fetchLocales = async () => {
51+
const result = await new TurLocaleService().query();
52+
setLocales(result);
53+
};
54+
fetchLocales();
55+
}, []);
56+
57+
async function onSubmit(snLocale: TurSNSiteLocale) {
58+
try {
59+
if (isNew) {
60+
const result = await turSNSiteLocaleService.create(snSiteId, snLocale);
61+
if (result) {
62+
toast.success(`The ${snLocale.language} SN Locale was created`);
63+
navigate(urlBase);
64+
}
65+
else {
66+
toast.error("Failed to create the SN Locale. Please try again.");
67+
}
68+
}
69+
else {
70+
const result = await turSNSiteLocaleService.update(snSiteId, snLocale);
71+
if (result) {
72+
toast.success(`The ${snLocale.language} SN Locale was updated`);
73+
}
74+
else {
75+
toast.error("Failed to update the SN Locale. Please try again.");
76+
}
77+
}
78+
} catch (error) {
79+
console.error("Form submission error", error);
80+
toast.error("Failed to submit the form. Please try again.");
81+
}
82+
}
83+
84+
return (
85+
<Form {...form}>
86+
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8 py-8 pr-8">
87+
<FormField
88+
control={form.control}
89+
name="language"
90+
render={({ field }) => (
91+
<FormItem>
92+
<FormLabel>Language</FormLabel>
93+
<Select onValueChange={field.onChange} value={field.value}>
94+
<FormControl>
95+
<SelectTrigger>
96+
<SelectValue placeholder="Choose..." />
97+
</SelectTrigger>
98+
</FormControl>
99+
<SelectContent>
100+
{locales.map((locale) => (
101+
<SelectItem key={locale.initials} value={locale.initials}>
102+
{locale.en} ({locale.initials})
103+
</SelectItem>
104+
))}
105+
</SelectContent>
106+
</Select>
107+
<FormDescription>
108+
Select the language code used for semantic search and content indexing.
109+
</FormDescription>
110+
<FormMessage />
111+
</FormItem>
112+
)}
113+
/>
114+
115+
<FormField
116+
control={form.control}
117+
name="core"
118+
render={({ field }) => (
119+
<FormItem>
120+
<FormLabel>Core</FormLabel>
121+
<FormControl>
122+
<Input
123+
{...field}
124+
placeholder="Core"
125+
type="text"
126+
/>
127+
</FormControl>
128+
<FormDescription>Core will appear on semantic navigation site locale list.</FormDescription>
129+
<FormMessage />
130+
</FormItem>
131+
)}
132+
/>
133+
<Button type="submit">Save</Button>
134+
</form>
135+
</Form>
136+
)
137+
}
138+

0 commit comments

Comments
 (0)