Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/[locale]/(user)/components/Content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ export const Content = () => {
<Text
color="onBgDefault"
fontWeight="semibold"
className="text-xs uppercase text-textSurfaceStats"
className="whitespace-nowrap text-xs uppercase text-textSurfaceStats"
>
{item.label}
</Text>
Expand Down
4 changes: 2 additions & 2 deletions app/[locale]/(user)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ export default function Layout({ children }: UserLayoutProps) {
}

return (
<div className="flex h-full grow flex-col">
<div className="flex min-h-screen flex-col">
<header className="z-1 sticky top-0 bg-primaryBlue">
<MainNav hideSearch={hideSearch} />
</header>
<>{children}</>
<main className="grow">{children}</main>
<footer>
<MainFooter />
</footer>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
'use client';

import { useEffect, useState } from 'react';
import { useParams } from 'next/navigation';
import { graphql } from '@/gql';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { useParams } from 'next/navigation';
import {
Checkbox,
Combobox,
Expand All @@ -14,7 +15,6 @@ import {
TextField,
toast,
} from 'opub-ui';
import { useEffect, useState } from 'react';

import { GraphQL } from '@/lib/api';
import RichTextEditor from '@/components/RichTextEditor/RichTextEditor';
Expand Down Expand Up @@ -124,6 +124,8 @@ export default function AIModelDetailsPage() {
});

const [isTagsListUpdated, setIsTagsListUpdated] = useState(false);
const SAVE_SUCCESS_TOAST_ID = 'ai-model-details-save-success';
const SAVE_ERROR_TOAST_ID = 'ai-model-details-save-error';
const isValidHttpUrl = (value: string) => {
try {
const parsed = new URL(value);
Expand Down Expand Up @@ -213,7 +215,7 @@ export default function AIModelDetailsPage() {
),
{
onSuccess: () => {
toast('AI Model updated successfully');
toast('AI Model updated successfully', { id: SAVE_SUCCESS_TOAST_ID });
setStatus('saved');
if (isTagsListUpdated) {
getTagsList.refetch();
Expand All @@ -223,7 +225,11 @@ export default function AIModelDetailsPage() {
queryClient.invalidateQueries([`fetch_AIModelForPublish_${params.id}`]);
},
onError: (error: any) => {
toast(`Error: ${error.message}`);
const errorMessage =
typeof error?.message === 'string' && error.message.trim()
? error.message.trim()
: 'Unable to update AI Model right now. Please try again.';
toast(`Error: ${errorMessage}`, { id: SAVE_ERROR_TOAST_ID });
setStatus('unsaved');
},
}
Expand Down Expand Up @@ -312,14 +318,14 @@ export default function AIModelDetailsPage() {
const handleSave = (overrideData?: any) => {
setStatus('saving');
const dataToUse = overrideData || formData;

// Ensure access type is always 'open' (required field)
if (dataToUse.accessType !== 'open') {
toast('Open access is required for all models');
setStatus('unsaved');
return;
}

const updateData: any = {
description: dataToUse.description,
modelType: dataToUse.modelType,
Expand Down Expand Up @@ -634,9 +640,7 @@ export default function AIModelDetailsPage() {
>
<div className="flex flex-col gap-1">
<Text>Open Access</Text>
<Text>
Model can be viewed and used by everyone
</Text>
<Text>Model can be viewed and used by everyone</Text>
</div>
</Checkbox>
<Checkbox
Expand All @@ -646,9 +650,7 @@ export default function AIModelDetailsPage() {
disabled
>
<div className="flex flex-col gap-1" title="Coming Soon">
<Text className="text-textDisabled">
Restricted Access
</Text>
<Text className="text-textDisabled">Restricted Access</Text>
<Text className="text-iconDisabled">
Users would require to request access to the model.
Recommended for sensitive models.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
'use client';

import { useParams, useRouter } from 'next/navigation';
import { graphql } from '@/gql';
import { useMutation, useQuery } from '@tanstack/react-query';
import { useParams, useRouter } from 'next/navigation';
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
Button,
Icon,
Spinner,
Table,
Tag,
Text,
toast,
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
Button,
Icon,
Spinner,
Table,
Tag,
Text,
toast,
} from 'opub-ui';

import { GraphQL } from '@/lib/api';
import { Icons } from '@/components/icons';
import { RichTextRenderer } from '@/components/RichTextRenderer';
import { GraphQL } from '@/lib/api';
import { useEditStatus } from '../../context';

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

const { mutate, isLoading: updateLoading } = useMutation(
(mutationData: any) =>
Expand All @@ -188,17 +190,7 @@ export default function PublishPage() {
},
}
),
{
onSuccess: () => {
toast('Model status updated successfully');
setStatus('saved');
refetch();
},
onError: (error: any) => {
toast(`Error: ${error.message}`);
setStatus('unsaved');
},
}
{}
);

const handlePublish = () => {
Expand All @@ -211,8 +203,22 @@ export default function PublishPage() {
},
{
onSuccess: () => {
toast('Model published successfully');
router.push(`/dashboard/${params.entityType}/${params.entitySlug}/aimodels`);
toast('Model published successfully', {
id: PUBLISH_SUCCESS_TOAST_ID,
});
setStatus('saved');
refetch();
router.push(
`/dashboard/${params.entityType}/${params.entitySlug}/aimodels`
);
},
onError: (error: any) => {
const errorMessage =
typeof error?.message === 'string' && error.message.trim()
? error.message.trim()
: 'Unable to publish model right now. Please try again.';
toast(`Error: ${errorMessage}`, { id: PUBLISH_ERROR_TOAST_ID });
setStatus('unsaved');
},
}
);
Expand All @@ -224,14 +230,15 @@ export default function PublishPage() {
if (!model?.tags?.length) metadataErrors.push('Tags');
if (!model?.sectors?.length) metadataErrors.push('Sectors');
if (!model?.geographies?.length) metadataErrors.push('Geographies');

// Check required fields from metadata
const metadata = model?.metadata || {};
if (!metadata.targetUsers) metadataErrors.push('Target Users');
if (!metadata.intendedUse) metadataErrors.push('Intended Use');
if (!metadata.modelWebsite) metadataErrors.push('Model Website');
if (!model?.maxTokens) metadataErrors.push('Maximum Tokens');
if (!model?.supportedLanguages?.length) metadataErrors.push('Supported Languages');
if (!model?.supportedLanguages?.length)
metadataErrors.push('Supported Languages');
if (!model?.modelType) metadataErrors.push('Model Type');

const versionErrors = [];
Expand Down Expand Up @@ -271,7 +278,9 @@ export default function PublishPage() {
version: v.version,
lifecycleStage: lifecycleLabels[v.lifecycleStage] || v.lifecycleStage,
providers: v.providers?.length
? v.providers.map((p: any) => providerLabels[p.provider] || p.provider).join(', ')
? v.providers
.map((p: any) => providerLabels[p.provider] || p.provider)
.join(', ')
: 'None',
primary: v.isLatest ? 'Yes' : 'No',
}));
Expand All @@ -288,7 +297,7 @@ export default function PublishPage() {
},
{
label: 'Domain',
value: model?.domain ? (domainLabels[model.domain] || model.domain) : '',
value: model?.domain ? domainLabels[model.domain] || model.domain : '',
},
{
label: 'Target Users',
Expand All @@ -308,7 +317,9 @@ export default function PublishPage() {
},
{
label: 'Supported Languages',
value: model?.supportedLanguages?.length ? model.supportedLanguages.join(', ') : '',
value: model?.supportedLanguages?.length
? model.supportedLanguages.join(', ')
: '',
},
];

Expand Down Expand Up @@ -391,10 +402,7 @@ export default function PublishPage() {

{model?.description && (
<div className="flex flex-wrap gap-2">
<Text
className="lg:basis-1/6"
variant="bodyMd"
>
<Text className="lg:basis-1/6" variant="bodyMd">
Description:
</Text>
<div className="lg:basis-4/5">
Expand All @@ -411,11 +419,9 @@ export default function PublishPage() {
</Text>
<div className="flex gap-2 lg:basis-4/5">
{model?.sectors?.length > 0 ? (
model.sectors.map(
(s: any, idx: number) => (
<Tag key={idx}>{s.name}</Tag>
)
)
model.sectors.map((s: any, idx: number) => (
<Tag key={idx}>{s.name}</Tag>
))
) : (
<Text variant="bodyMd" color="subdued">
None
Expand All @@ -430,11 +436,9 @@ export default function PublishPage() {
</Text>
<div className="flex gap-2 lg:basis-4/5">
{model?.tags?.length > 0 ? (
model.tags.map(
(t: any, idx: number) => (
<Tag key={idx}>{t.value}</Tag>
)
)
model.tags.map((t: any, idx: number) => (
<Tag key={idx}>{t.value}</Tag>
))
) : (
<Text variant="bodyMd" color="subdued">
None
Expand Down Expand Up @@ -472,7 +476,11 @@ export default function PublishPage() {
hideFooter
/>
) : (
<Text variant="bodyMd" color="subdued" className="px-4 py-2">
<Text
variant="bodyMd"
color="subdued"
className="px-4 py-2"
>
No versions found
</Text>
)}
Expand All @@ -486,27 +494,27 @@ export default function PublishPage() {

{/* Publication Status */}
{isPublished ? (
<div className="rounded-1 border border-tertiaryAccent bg-tertiaryAccent/10 p-4">
<div className="border bg-tertiaryAccent/10 rounded-1 border-tertiaryAccent p-4">
<div className="flex items-center gap-2">
<Icon source={Icons.check} color="success" size={24} />
<Text variant="headingSm" className="text-primaryText">
Model is Published and Active
</Text>
</div>
<Text variant="bodySm" className="mt-2 text-primaryText/80">
<Text variant="bodySm" className="text-primaryText/80 mt-2">
Your AI model is now publicly accessible and can be
discovered by other users.
</Text>
</div>
) : (
<div className="rounded-1 border border-secondaryOrange bg-secondaryOrange/10 p-4">
<div className="border bg-secondaryOrange/10 rounded-1 border-secondaryOrange p-4">
<div className="flex items-center gap-2">
<Icon source={Icons.alert} color="warning" size={24} />
<Text variant="headingSm" className="text-secondaryText">
Model is not published
</Text>
</div>
<Text variant="bodySm" className="mt-2 text-secondaryText/80">
<Text variant="bodySm" className="text-secondaryText/80 mt-2">
{!isPublishDisabled
? 'All checklist items are complete. You can now publish your model.'
: 'Complete all required fields before publishing your model.'}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Link from 'next/link';
import { Text } from 'opub-ui';

import { getWebsiteTitle } from '@/lib/utils';
import { RichTextRenderer } from '@/components/RichTextRenderer';

const Details = ({ data }: { data: any }) => {
const [platformTitle, setPlatformTitle] = useState<string | null>(null);
Expand Down Expand Up @@ -60,7 +61,14 @@ const Details = ({ data }: { data: any }) => {
<Text variant="bodyMd">{item.label}:</Text>
</div>
<div>
<Text variant="bodyMd">{item.value}</Text>
{item.label === 'Summary' ? (
<RichTextRenderer
content={item.value}
className="text-black"
/>
) : (
<Text variant="bodyMd">{item.value}</Text>
)}
</div>
</div>
)
Expand Down
Loading