Skip to content

Commit ae1b7a5

Browse files
Merge pull request #375 from CivicDataLab/fix/quill
2 parents afd08f5 + 3127fc7 commit ae1b7a5

26 files changed

Lines changed: 594 additions & 201 deletions

File tree

app/[locale]/(user)/components/Content.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ export const Content = () => {
122122
<Text
123123
color="onBgDefault"
124124
fontWeight="semibold"
125-
className="text-xs uppercase text-textSurfaceStats"
125+
className="whitespace-nowrap text-xs uppercase text-textSurfaceStats"
126126
>
127127
{item.label}
128128
</Text>

app/[locale]/(user)/layout.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ export default function Layout({ children }: UserLayoutProps) {
2020
}
2121

2222
return (
23-
<div className="flex h-full grow flex-col">
23+
<div className="flex min-h-screen flex-col">
2424
<header className="z-1 sticky top-0 bg-primaryBlue">
2525
<MainNav hideSearch={hideSearch} />
2626
</header>
27-
<>{children}</>
27+
<main className="grow">{children}</main>
2828
<footer>
2929
<MainFooter />
3030
</footer>

app/[locale]/dashboard/[entityType]/[entitySlug]/aimodels/edit/[id]/details/page.tsx

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
'use client';
22

3+
import { useEffect, useState } from 'react';
4+
import { useParams } from 'next/navigation';
35
import { graphql } from '@/gql';
46
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
5-
import { useParams } from 'next/navigation';
67
import {
78
Checkbox,
89
Combobox,
@@ -14,7 +15,6 @@ import {
1415
TextField,
1516
toast,
1617
} from 'opub-ui';
17-
import { useEffect, useState } from 'react';
1818

1919
import { GraphQL } from '@/lib/api';
2020
import RichTextEditor from '@/components/RichTextEditor/RichTextEditor';
@@ -124,6 +124,8 @@ export default function AIModelDetailsPage() {
124124
});
125125

126126
const [isTagsListUpdated, setIsTagsListUpdated] = useState(false);
127+
const SAVE_SUCCESS_TOAST_ID = 'ai-model-details-save-success';
128+
const SAVE_ERROR_TOAST_ID = 'ai-model-details-save-error';
127129
const isValidHttpUrl = (value: string) => {
128130
try {
129131
const parsed = new URL(value);
@@ -213,7 +215,7 @@ export default function AIModelDetailsPage() {
213215
),
214216
{
215217
onSuccess: () => {
216-
toast('AI Model updated successfully');
218+
toast('AI Model updated successfully', { id: SAVE_SUCCESS_TOAST_ID });
217219
setStatus('saved');
218220
if (isTagsListUpdated) {
219221
getTagsList.refetch();
@@ -223,7 +225,11 @@ export default function AIModelDetailsPage() {
223225
queryClient.invalidateQueries([`fetch_AIModelForPublish_${params.id}`]);
224226
},
225227
onError: (error: any) => {
226-
toast(`Error: ${error.message}`);
228+
const errorMessage =
229+
typeof error?.message === 'string' && error.message.trim()
230+
? error.message.trim()
231+
: 'Unable to update AI Model right now. Please try again.';
232+
toast(`Error: ${errorMessage}`, { id: SAVE_ERROR_TOAST_ID });
227233
setStatus('unsaved');
228234
},
229235
}
@@ -312,14 +318,14 @@ export default function AIModelDetailsPage() {
312318
const handleSave = (overrideData?: any) => {
313319
setStatus('saving');
314320
const dataToUse = overrideData || formData;
315-
321+
316322
// Ensure access type is always 'open' (required field)
317323
if (dataToUse.accessType !== 'open') {
318324
toast('Open access is required for all models');
319325
setStatus('unsaved');
320326
return;
321327
}
322-
328+
323329
const updateData: any = {
324330
description: dataToUse.description,
325331
modelType: dataToUse.modelType,
@@ -634,9 +640,7 @@ export default function AIModelDetailsPage() {
634640
>
635641
<div className="flex flex-col gap-1">
636642
<Text>Open Access</Text>
637-
<Text>
638-
Model can be viewed and used by everyone
639-
</Text>
643+
<Text>Model can be viewed and used by everyone</Text>
640644
</div>
641645
</Checkbox>
642646
<Checkbox
@@ -646,9 +650,7 @@ export default function AIModelDetailsPage() {
646650
disabled
647651
>
648652
<div className="flex flex-col gap-1" title="Coming Soon">
649-
<Text className="text-textDisabled">
650-
Restricted Access
651-
</Text>
653+
<Text className="text-textDisabled">Restricted Access</Text>
652654
<Text className="text-iconDisabled">
653655
Users would require to request access to the model.
654656
Recommended for sensitive models.

app/[locale]/dashboard/[entityType]/[entitySlug]/aimodels/edit/[id]/publish/page.tsx

Lines changed: 58 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
'use client';
22

3+
import { useParams, useRouter } from 'next/navigation';
34
import { graphql } from '@/gql';
45
import { useMutation, useQuery } from '@tanstack/react-query';
5-
import { useParams, useRouter } from 'next/navigation';
66
import {
7-
Accordion,
8-
AccordionContent,
9-
AccordionItem,
10-
AccordionTrigger,
11-
Button,
12-
Icon,
13-
Spinner,
14-
Table,
15-
Tag,
16-
Text,
17-
toast,
7+
Accordion,
8+
AccordionContent,
9+
AccordionItem,
10+
AccordionTrigger,
11+
Button,
12+
Icon,
13+
Spinner,
14+
Table,
15+
Tag,
16+
Text,
17+
toast,
1818
} from 'opub-ui';
1919

20+
import { GraphQL } from '@/lib/api';
2021
import { Icons } from '@/components/icons';
2122
import { RichTextRenderer } from '@/components/RichTextRenderer';
22-
import { GraphQL } from '@/lib/api';
2323
import { useEditStatus } from '../../context';
2424

2525
const FetchAIModelForPublish: any = graphql(`
@@ -173,6 +173,8 @@ export default function PublishPage() {
173173
const versions = model?.versions || [];
174174
const primaryVersion = versions.find((v: any) => v.isLatest) || versions[0];
175175
const hasProviders = versions.some((v: any) => v.providers?.length > 0);
176+
const PUBLISH_SUCCESS_TOAST_ID = 'publish-ai-model-success';
177+
const PUBLISH_ERROR_TOAST_ID = 'publish-ai-model-error';
176178

177179
const { mutate, isLoading: updateLoading } = useMutation(
178180
(mutationData: any) =>
@@ -188,17 +190,7 @@ export default function PublishPage() {
188190
},
189191
}
190192
),
191-
{
192-
onSuccess: () => {
193-
toast('Model status updated successfully');
194-
setStatus('saved');
195-
refetch();
196-
},
197-
onError: (error: any) => {
198-
toast(`Error: ${error.message}`);
199-
setStatus('unsaved');
200-
},
201-
}
193+
{}
202194
);
203195

204196
const handlePublish = () => {
@@ -211,8 +203,22 @@ export default function PublishPage() {
211203
},
212204
{
213205
onSuccess: () => {
214-
toast('Model published successfully');
215-
router.push(`/dashboard/${params.entityType}/${params.entitySlug}/aimodels`);
206+
toast('Model published successfully', {
207+
id: PUBLISH_SUCCESS_TOAST_ID,
208+
});
209+
setStatus('saved');
210+
refetch();
211+
router.push(
212+
`/dashboard/${params.entityType}/${params.entitySlug}/aimodels`
213+
);
214+
},
215+
onError: (error: any) => {
216+
const errorMessage =
217+
typeof error?.message === 'string' && error.message.trim()
218+
? error.message.trim()
219+
: 'Unable to publish model right now. Please try again.';
220+
toast(`Error: ${errorMessage}`, { id: PUBLISH_ERROR_TOAST_ID });
221+
setStatus('unsaved');
216222
},
217223
}
218224
);
@@ -224,14 +230,15 @@ export default function PublishPage() {
224230
if (!model?.tags?.length) metadataErrors.push('Tags');
225231
if (!model?.sectors?.length) metadataErrors.push('Sectors');
226232
if (!model?.geographies?.length) metadataErrors.push('Geographies');
227-
233+
228234
// Check required fields from metadata
229235
const metadata = model?.metadata || {};
230236
if (!metadata.targetUsers) metadataErrors.push('Target Users');
231237
if (!metadata.intendedUse) metadataErrors.push('Intended Use');
232238
if (!metadata.modelWebsite) metadataErrors.push('Model Website');
233239
if (!model?.maxTokens) metadataErrors.push('Maximum Tokens');
234-
if (!model?.supportedLanguages?.length) metadataErrors.push('Supported Languages');
240+
if (!model?.supportedLanguages?.length)
241+
metadataErrors.push('Supported Languages');
235242
if (!model?.modelType) metadataErrors.push('Model Type');
236243

237244
const versionErrors = [];
@@ -271,7 +278,9 @@ export default function PublishPage() {
271278
version: v.version,
272279
lifecycleStage: lifecycleLabels[v.lifecycleStage] || v.lifecycleStage,
273280
providers: v.providers?.length
274-
? v.providers.map((p: any) => providerLabels[p.provider] || p.provider).join(', ')
281+
? v.providers
282+
.map((p: any) => providerLabels[p.provider] || p.provider)
283+
.join(', ')
275284
: 'None',
276285
primary: v.isLatest ? 'Yes' : 'No',
277286
}));
@@ -288,7 +297,7 @@ export default function PublishPage() {
288297
},
289298
{
290299
label: 'Domain',
291-
value: model?.domain ? (domainLabels[model.domain] || model.domain) : '',
300+
value: model?.domain ? domainLabels[model.domain] || model.domain : '',
292301
},
293302
{
294303
label: 'Target Users',
@@ -308,7 +317,9 @@ export default function PublishPage() {
308317
},
309318
{
310319
label: 'Supported Languages',
311-
value: model?.supportedLanguages?.length ? model.supportedLanguages.join(', ') : '',
320+
value: model?.supportedLanguages?.length
321+
? model.supportedLanguages.join(', ')
322+
: '',
312323
},
313324
];
314325

@@ -391,10 +402,7 @@ export default function PublishPage() {
391402

392403
{model?.description && (
393404
<div className="flex flex-wrap gap-2">
394-
<Text
395-
className="lg:basis-1/6"
396-
variant="bodyMd"
397-
>
405+
<Text className="lg:basis-1/6" variant="bodyMd">
398406
Description:
399407
</Text>
400408
<div className="lg:basis-4/5">
@@ -411,11 +419,9 @@ export default function PublishPage() {
411419
</Text>
412420
<div className="flex gap-2 lg:basis-4/5">
413421
{model?.sectors?.length > 0 ? (
414-
model.sectors.map(
415-
(s: any, idx: number) => (
416-
<Tag key={idx}>{s.name}</Tag>
417-
)
418-
)
422+
model.sectors.map((s: any, idx: number) => (
423+
<Tag key={idx}>{s.name}</Tag>
424+
))
419425
) : (
420426
<Text variant="bodyMd" color="subdued">
421427
None
@@ -430,11 +436,9 @@ export default function PublishPage() {
430436
</Text>
431437
<div className="flex gap-2 lg:basis-4/5">
432438
{model?.tags?.length > 0 ? (
433-
model.tags.map(
434-
(t: any, idx: number) => (
435-
<Tag key={idx}>{t.value}</Tag>
436-
)
437-
)
439+
model.tags.map((t: any, idx: number) => (
440+
<Tag key={idx}>{t.value}</Tag>
441+
))
438442
) : (
439443
<Text variant="bodyMd" color="subdued">
440444
None
@@ -472,7 +476,11 @@ export default function PublishPage() {
472476
hideFooter
473477
/>
474478
) : (
475-
<Text variant="bodyMd" color="subdued" className="px-4 py-2">
479+
<Text
480+
variant="bodyMd"
481+
color="subdued"
482+
className="px-4 py-2"
483+
>
476484
No versions found
477485
</Text>
478486
)}
@@ -486,27 +494,27 @@ export default function PublishPage() {
486494

487495
{/* Publication Status */}
488496
{isPublished ? (
489-
<div className="rounded-1 border border-tertiaryAccent bg-tertiaryAccent/10 p-4">
497+
<div className="border bg-tertiaryAccent/10 rounded-1 border-tertiaryAccent p-4">
490498
<div className="flex items-center gap-2">
491499
<Icon source={Icons.check} color="success" size={24} />
492500
<Text variant="headingSm" className="text-primaryText">
493501
Model is Published and Active
494502
</Text>
495503
</div>
496-
<Text variant="bodySm" className="mt-2 text-primaryText/80">
504+
<Text variant="bodySm" className="text-primaryText/80 mt-2">
497505
Your AI model is now publicly accessible and can be
498506
discovered by other users.
499507
</Text>
500508
</div>
501509
) : (
502-
<div className="rounded-1 border border-secondaryOrange bg-secondaryOrange/10 p-4">
510+
<div className="border bg-secondaryOrange/10 rounded-1 border-secondaryOrange p-4">
503511
<div className="flex items-center gap-2">
504512
<Icon source={Icons.alert} color="warning" size={24} />
505513
<Text variant="headingSm" className="text-secondaryText">
506514
Model is not published
507515
</Text>
508516
</div>
509-
<Text variant="bodySm" className="mt-2 text-secondaryText/80">
517+
<Text variant="bodySm" className="text-secondaryText/80 mt-2">
510518
{!isPublishDisabled
511519
? 'All checklist items are complete. You can now publish your model.'
512520
: 'Complete all required fields before publishing your model.'}

app/[locale]/dashboard/[entityType]/[entitySlug]/collaboratives/edit/[id]/publish/Details.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import Link from 'next/link';
44
import { Text } from 'opub-ui';
55

66
import { getWebsiteTitle } from '@/lib/utils';
7+
import { RichTextRenderer } from '@/components/RichTextRenderer';
78

89
const Details = ({ data }: { data: any }) => {
910
const [platformTitle, setPlatformTitle] = useState<string | null>(null);
@@ -60,7 +61,14 @@ const Details = ({ data }: { data: any }) => {
6061
<Text variant="bodyMd">{item.label}:</Text>
6162
</div>
6263
<div>
63-
<Text variant="bodyMd">{item.value}</Text>
64+
{item.label === 'Summary' ? (
65+
<RichTextRenderer
66+
content={item.value}
67+
className="text-black"
68+
/>
69+
) : (
70+
<Text variant="bodyMd">{item.value}</Text>
71+
)}
6472
</div>
6573
</div>
6674
)

0 commit comments

Comments
 (0)