Skip to content

Commit eed469c

Browse files
committed
WIP: new settings page
1 parent 6625a8e commit eed469c

7 files changed

Lines changed: 293 additions & 5 deletions

File tree

packages/app-builder/src/locales/ar/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"data_display.global_explanation": "اسحب الحقول وإسقاطها لتعيين ترتيب العرض ، واستخدم Toggle لإخفاء تلك التي لا تحتاجها افتراضيًا في مدير الحالة.",
1919
"global_settings.auto_assign_queue_limit": "حد التعيين التلقائي",
2020
"global_settings.title": "الإعدادات العامة",
21+
"ia_case_review": "مراجعة الحالات بالذكاء الاصطناعي",
2122
"inboxes": "صناديق البريدالوارد",
2223
"inboxes.auto_assign_queue_limit.nudge": "يسمح التعيين التلقائي بتوزيع الحالات بين المستخدمين.",
2324
"inboxes.cases": "الحالات",

packages/app-builder/src/locales/en/settings.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@
1818
"data_display.global_explanation": "Drag and drop the fields to set the display order, and use the toggle to hide those not needed by default in the case manager.",
1919
"global_settings.auto_assign_queue_limit": "Auto assign queue limit",
2020
"global_settings.title": "Global settings",
21+
"ia_case_review": "IA Case Review - General",
22+
"ia_case_review.language": "Output language",
23+
"ia_case_review.org_description": "Organization description",
24+
"ia_case_review.structure": "Desired review structure",
25+
"ia_llm_config": "LLM configuration",
26+
"ia_llm_config.llm_model": "LLM model",
27+
"ia_llm_config.search_context_size": "Search context size",
2128
"inboxes": "Inboxes",
2229
"inboxes.auto_assign_queue_limit.nudge": "The auto assignment allows to automatically distribute cases between reviewers agents.",
2330
"inboxes.cases": "Cases",

packages/app-builder/src/locales/fr/settings.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,16 @@
1818
"data_display.global_explanation": "Faites glisser et déposez les champs pour définir l'ordre d'affichage et utilisez le switch pour masquer ceux qui ne sont pas nécessaires par défaut dans la page d'investigations.",
1919
"global_settings.auto_assign_queue_limit": "Limite d'assignation automatique",
2020
"global_settings.title": "Paramètres globaux",
21+
"ia_case_review": "Analyse IA - Général",
22+
"ia_case_review.domain_filter": "Filtre de domaine",
23+
"ia_case_review.language": "Langue d'affichage",
24+
"ia_case_review.llm_model": "Modèle LLM",
25+
"ia_case_review.org_description": "Description de l'organisation",
26+
"ia_case_review.search_context_size": "Taille du contexte de recherche",
27+
"ia_case_review.structure": "Structure de l'analyse souhaitée",
28+
"ia_llm_config": "Configuration LLM",
29+
"ia_llm_config.llm_model": "Modèle LLM",
30+
"ia_llm_config.search_context_size": "Taille du contexte de recherche",
2131
"inboxes": "Boîtes de réception",
2232
"inboxes.auto_assign_queue_limit.nudge": "L'assignation automatique permet de distribuer automatiquement les investigations aux agents.",
2333
"inboxes.cases": "Investigation",

packages/app-builder/src/routes/_builder+/settings+/_layout.tsx

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,18 @@ export function getSettings(user: CurrentUser, inboxes: Inbox[]) {
8585
});
8686
}
8787
if (isAdmin(user)) {
88-
settings.push({
89-
section: 'case_manager' as const,
90-
title: 'data_display' as const,
91-
to: getRoute('/settings/data-display'),
92-
});
88+
settings.push(
89+
{
90+
section: 'case_manager' as const,
91+
title: 'ia_case_review' as const,
92+
to: getRoute('/settings/ia-case-review'),
93+
},
94+
{
95+
section: 'case_manager' as const,
96+
title: 'data_display' as const,
97+
to: getRoute('/settings/data-display'),
98+
},
99+
);
93100
}
94101
return settings;
95102
}
Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
import { FormLabel } from '@app-builder/components/Form/Tanstack/FormLabel';
2+
import { FormTextArea } from '@app-builder/components/Form/Tanstack/FormTextArea';
3+
4+
import { Page } from '@app-builder/components/Page';
5+
import { CollapsiblePaper } from '@app-builder/components/Paper';
6+
import { initServerServices } from '@app-builder/services/init.server';
7+
import { getRoute } from '@app-builder/utils/routes';
8+
import { type LoaderFunctionArgs } from '@remix-run/node';
9+
import { useLoaderData } from '@remix-run/react';
10+
import { useForm } from '@tanstack/react-form';
11+
import { useTranslation } from 'react-i18next';
12+
import { Button, MenuCommand } from 'ui-design-system';
13+
14+
import { z } from 'zod/v4';
15+
16+
export async function loader({ request }: LoaderFunctionArgs) {
17+
const { authService } = initServerServices(request);
18+
const { user } = await authService.isAuthenticated(request, {
19+
failureRedirect: getRoute('/sign-in'),
20+
});
21+
22+
return { user };
23+
}
24+
25+
/* Mock data */
26+
// Supported languages list. use BCP47 format.
27+
const supportedLanguages = ['en', 'fr', 'ar'];
28+
29+
// Structure : The desired output structure of the IA report. Free text defined by the user. (e.g. "The report should be in the following format: <name>, <age>, <gender>, <address>, <phone number>, <email>, <nationality>, <occupation>, <income>, <assets>, <liabilities>, <net worth>, <source of income>, <source of assets>, <source of liabilities>, <source of net worth>")
30+
// Org description : The description of the organization.
31+
32+
// Supported LLM models list.
33+
const supportedLLMModels = ['gpt-4o', 'gpt-4o-mini', 'claude-3-5-sonnet-20240620'];
34+
35+
// Domain filter for KYC enrichment : Free array of string domains.
36+
37+
// Search context size (PerplexitySearchContextSize)
38+
const supportedSearchContextSizes = [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000];
39+
40+
const editIACaseReviewSchema = z.object({
41+
language: z.enum(supportedLanguages),
42+
structure: z.string(),
43+
orgDescription: z.string(),
44+
llmModel: z.enum(supportedLLMModels),
45+
domainFilter: z.array(z.string()),
46+
searchContextSize: z.enum(supportedSearchContextSizes.map(String)),
47+
});
48+
49+
export default function IACaseReviewSettings() {
50+
const { t } = useTranslation(['settings']);
51+
const { user } = useLoaderData<typeof loader>();
52+
const form = useForm({
53+
onSubmit: ({ value, formApi }) => {
54+
if (formApi.state.isValid) {
55+
//TODO: Create a query mutation to update the IA case review settings.
56+
// Mock for now
57+
console.log('value', value);
58+
// setToastMessage(session, {
59+
// type: 'success',
60+
// messageKey: 'common:success.save',
61+
// });
62+
}
63+
},
64+
validators: {
65+
onSubmit: editIACaseReviewSchema as unknown as any,
66+
},
67+
defaultValues: {
68+
language: 'en',
69+
structure: '',
70+
orgDescription: '',
71+
llmModel: 'gpt-4o',
72+
domainFilter: [],
73+
searchContextSize: 100,
74+
},
75+
});
76+
console.log('user', user);
77+
return (
78+
<Page.Container>
79+
<Page.Content className="max-w-(--breakpoint-xl)">
80+
<form
81+
className="flex flex-col gap-4"
82+
onSubmit={(e) => {
83+
e.preventDefault();
84+
e.stopPropagation();
85+
form.handleSubmit();
86+
}}
87+
>
88+
<div className="flex flex-col gap-4">
89+
<CollapsiblePaper.Container>
90+
<CollapsiblePaper.Title>
91+
<span className="flex-1">{t('settings:ia_case_review')}</span>
92+
</CollapsiblePaper.Title>
93+
<CollapsiblePaper.Content>
94+
<div className="flex flex-col gap-8">
95+
{/* TODO: Add Org description */}
96+
<form.Field name="orgDescription">
97+
{(field) => (
98+
<div className="group flex w-full flex-col gap-2">
99+
<FormLabel name={field.name}>
100+
{t('settings:ia_case_review.org_description')}
101+
</FormLabel>
102+
<FormTextArea
103+
name={field.name}
104+
onChange={(e) => field.handleChange(e.currentTarget.value)}
105+
onBlur={field.handleBlur}
106+
defaultValue={field.state.value}
107+
valid={field.state.meta.errors.length === 0}
108+
/>
109+
</div>
110+
)}
111+
</form.Field>
112+
113+
{/* TODO: Add Language */}
114+
<form.Field name="language">
115+
{(field) => (
116+
<div className="group flex w-full flex-col gap-2">
117+
<FormLabel name={field.name}>
118+
{t('settings:ia_case_review.language')}
119+
</FormLabel>
120+
<MenuCommand.Menu>
121+
<MenuCommand.Trigger>
122+
<MenuCommand.SelectButton>{field.state.value}</MenuCommand.SelectButton>
123+
</MenuCommand.Trigger>
124+
125+
<MenuCommand.Content
126+
sameWidth
127+
sideOffset={4}
128+
align="start"
129+
className="min-w-24"
130+
>
131+
<MenuCommand.List>
132+
{supportedLanguages.map((language) => (
133+
<MenuCommand.Item
134+
key={language}
135+
value={language}
136+
onSelect={() => field.handleChange(language)}
137+
>
138+
{language}
139+
</MenuCommand.Item>
140+
))}
141+
</MenuCommand.List>
142+
</MenuCommand.Content>
143+
</MenuCommand.Menu>
144+
</div>
145+
)}
146+
</form.Field>
147+
{/* TODO: Add Structure */}
148+
<form.Field name="structure">
149+
{(field) => (
150+
<div className="group flex w-full flex-col gap-2">
151+
<FormLabel name={field.name}>
152+
{t('settings:ia_case_review.structure')}
153+
</FormLabel>
154+
<FormTextArea
155+
name={field.name}
156+
onChange={(e) => field.handleChange(e.currentTarget.value)}
157+
onBlur={field.handleBlur}
158+
defaultValue={field.state.value}
159+
valid={field.state.meta.errors.length === 0}
160+
/>
161+
</div>
162+
)}
163+
</form.Field>
164+
</div>
165+
</CollapsiblePaper.Content>
166+
</CollapsiblePaper.Container>
167+
{/* TODO: Add LLM Model */}
168+
<CollapsiblePaper.Container>
169+
<CollapsiblePaper.Title>
170+
<span className="flex-1">{t('settings:ia_llm_config')}</span>
171+
</CollapsiblePaper.Title>
172+
<CollapsiblePaper.Content>
173+
<div className="flex flex-col gap-8">
174+
{/* TODO: Add LLM Model */}
175+
<form.Field name="llmModel">
176+
{(field) => (
177+
<div className="group flex w-full flex-col gap-2">
178+
<FormLabel name={field.name}>
179+
{t('settings:ia_llm_config.llm_model')}
180+
</FormLabel>
181+
<MenuCommand.Menu>
182+
<MenuCommand.Trigger>
183+
<MenuCommand.SelectButton>{field.state.value}</MenuCommand.SelectButton>
184+
</MenuCommand.Trigger>
185+
<MenuCommand.Content
186+
sameWidth
187+
sideOffset={4}
188+
align="start"
189+
className="min-w-24"
190+
>
191+
<MenuCommand.List>
192+
{supportedLLMModels.map((model) => (
193+
<MenuCommand.Item
194+
key={model}
195+
value={model}
196+
onSelect={() => field.handleChange(model)}
197+
>
198+
{model}
199+
</MenuCommand.Item>
200+
))}
201+
</MenuCommand.List>
202+
</MenuCommand.Content>
203+
</MenuCommand.Menu>
204+
</div>
205+
)}
206+
</form.Field>
207+
</div>
208+
209+
{/* TODO: Add Search Context Size */}
210+
211+
<form.Field name="searchContextSize">
212+
{(field) => (
213+
<div className="group flex w-full flex-col gap-2">
214+
<FormLabel name={field.name}>
215+
{t('settings:ia_llm_config.search_context_size')}
216+
</FormLabel>
217+
<MenuCommand.Menu>
218+
<MenuCommand.Trigger>
219+
<MenuCommand.SelectButton>{field.state.value}</MenuCommand.SelectButton>
220+
</MenuCommand.Trigger>
221+
222+
<MenuCommand.Content
223+
sameWidth
224+
sideOffset={4}
225+
align="start"
226+
className="min-w-24"
227+
>
228+
<MenuCommand.List>
229+
{supportedSearchContextSizes.map((size) => (
230+
<MenuCommand.Item
231+
key={size}
232+
value={size}
233+
onSelect={() => field.handleChange(size)}
234+
>
235+
{size}
236+
</MenuCommand.Item>
237+
))}
238+
</MenuCommand.List>
239+
</MenuCommand.Content>
240+
</MenuCommand.Menu>
241+
</div>
242+
)}
243+
</form.Field>
244+
</CollapsiblePaper.Content>
245+
</CollapsiblePaper.Container>
246+
{/* TODO: Add Domain Filter */}
247+
{/* TODO: Add Domain Filter */}
248+
</div>
249+
<Button type="submit" variant="primary">
250+
{t('common:save')}
251+
</Button>
252+
</form>
253+
</Page.Content>
254+
</Page.Container>
255+
);
256+
}

packages/app-builder/src/utils/routes/routes.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,11 @@ export const routes = [
283283
"path": "data-display",
284284
"file": "routes/_builder+/settings+/data-display.tsx"
285285
},
286+
{
287+
"id": "routes/_builder+/settings+/ia-case-review",
288+
"path": "ia-case-review",
289+
"file": "routes/_builder+/settings+/ia-case-review.tsx"
290+
},
286291
{
287292
"id": "routes/_builder+/settings+/inboxes.$inboxId",
288293
"path": "inboxes/:inboxId",

packages/app-builder/src/utils/routes/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export type RoutePath =
3939
| '/settings'
4040
| '/settings/api-keys'
4141
| '/settings/data-display'
42+
| '/settings/ia-case-review'
4243
| '/settings/inboxes/:inboxId'
4344
| '/settings/inboxes'
4445
| '/settings/scenarios'
@@ -215,6 +216,7 @@ export type RouteID =
215216
| 'routes/_builder+/settings+/_index'
216217
| 'routes/_builder+/settings+/api-keys'
217218
| 'routes/_builder+/settings+/data-display'
219+
| 'routes/_builder+/settings+/ia-case-review'
218220
| 'routes/_builder+/settings+/inboxes.$inboxId'
219221
| 'routes/_builder+/settings+/inboxes._index'
220222
| 'routes/_builder+/settings+/scenarios'

0 commit comments

Comments
 (0)