Skip to content

Commit

Permalink
Misc fixes & improvements (#127)
Browse files Browse the repository at this point in the history
* feat: check node status

* fix: connect page ui

* fix: external links

* fix: agent list

* fix: agent list

* fix: eslint

* feat: implement chat editor
  • Loading branch information
paulclindo authored Jan 30, 2024
1 parent eeef181 commit 21e5022
Show file tree
Hide file tree
Showing 20 changed files with 637 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,30 @@ export const ConnectMethodQuickStart = () => {
</Button>
</form>
</Form>
<div className="text-gray-80 space-y-4 py-8 pt-12 text-center text-sm">
<p>
Don’t have an account?{' '}
<a
className="font-semibold text-white underline"
href="https://develop.shinkai-website.pages.dev/sign-up"
rel="noreferrer"
target={'_blank'}
>
Sign up
</a>
</p>
<p>
Already have an account?{' '}
<a
className="font-semibold text-white underline"
href="https://develop.shinkai-website.pages.dev/user"
rel="noreferrer"
target={'_blank'}
>
Get shinkai node
</a>
</p>
</div>
</div>

<div className="flex gap-4">
Expand Down
5 changes: 1 addition & 4 deletions apps/shinkai-visor/src/components/create-job/create-job.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -177,10 +177,7 @@ export const CreateJob = () => {
<SelectContent>
{agents?.map((agent) => (
<SelectItem key={agent.id} value={agent.id}>
{
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(agent.full_identity_name as any)?.subidentity_name
}
{agent.id}
</SelectItem>
))}
</SelectContent>
Expand Down
18 changes: 7 additions & 11 deletions apps/shinkai-visor/src/components/inbox-input/inbox-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
Form,
FormField,
FormItem,
PromptTextarea,
MessageEditor,
} from '@shinkai_network/shinkai-ui';
import { motion } from 'framer-motion';
import { SendHorizonal } from 'lucide-react';
Expand Down Expand Up @@ -60,17 +60,12 @@ export const InboxInput = (props: InboxInputProps) => {
transition={{ type: 'tween' }}
>
<FormItem>
<PromptTextarea
autoFocus
field={field}
<MessageEditor
disabled={props.loading}
isLoading={props.loading}
label={intl.formatMessage({ id: 'tmwtd' })}
onKeyDown={(event) => {
if (event.key === 'Enter' && !event.shiftKey) {
event.preventDefault();
form.handleSubmit(submit)();
}
}}
onChange={field.onChange}
onSubmit={form.handleSubmit(submit)}
placeholder={intl.formatMessage({ id: 'tmwtd' })}
value={field.value}
/>
</FormItem>
Expand All @@ -91,6 +86,7 @@ export const InboxInput = (props: InboxInputProps) => {
}
>
<SendHorizonal className="h-6 w-6" />
<span className="sr-only">Send Message</span>
</Button>
</motion.div>
)}
Expand Down
6 changes: 5 additions & 1 deletion apps/shinkai-visor/src/components/message/message.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
MarkdownPreview,
} from '@shinkai_network/shinkai-ui';
import { cn } from '@shinkai_network/shinkai-ui/utils';
import React from 'react';

import shinkaiMiniLogo from '../../assets/icons/shinkai-min.svg';
import { srcUrlResolver } from '../../helpers/src-url-resolver';
Expand All @@ -25,7 +26,10 @@ const copyToClipboard = (content: string) => {
};

export const Message = ({ message }: MessageProps) => {
const openMarkdownLink = (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>, url?: string) => {
const openMarkdownLink = (
event: React.MouseEvent<HTMLAnchorElement, MouseEvent>,
url?: string,
) => {
event.preventDefault();
if (!url) return;
sendMessage({
Expand Down
3 changes: 1 addition & 2 deletions apps/shinkai-visor/src/components/nav/nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,6 @@ export default function NavBar() {
};

const onClickMenuOption = (key: MenuOption) => {
console.log('menu option', key, MenuOption.Settings);
switch (key) {
case MenuOption.Inbox:
history.push('/inboxes');
Expand Down Expand Up @@ -165,7 +164,7 @@ export default function NavBar() {
<div className="text-sm">
Before continuing, please
<Link
className="mr-1 inline-block cursor-pointer text-white underline"
className="mx-1 inline-block cursor-pointer text-white underline"
to={'/settings/export-connection'}
>
export your connection
Expand Down
3 changes: 2 additions & 1 deletion apps/shinkai-visor/src/components/popup/popup.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import '../../theme/styles.css';

import { queryClient } from '@shinkai_network/shinkai-node-state/lib/constants';
import { Toaster } from '@shinkai_network/shinkai-ui';
import { QueryClientProvider } from '@tanstack/react-query';
import { AnimatePresence, motion } from 'framer-motion';
import * as React from 'react';
Expand Down Expand Up @@ -29,7 +30,6 @@ import { Settings } from '../settings/settings';
import { SplashScreen } from '../splash-screen/splash-screen';
import Welcome from '../welcome/welcome';
import { WithNav } from '../with-nav/with-nav';

export const Popup = () => {
const history = useHistory();
const auth = useAuth((state) => state.auth);
Expand Down Expand Up @@ -150,6 +150,7 @@ root.render(
<Popup />
</Router>
</div>
<Toaster />
</IntlProvider>
</QueryClientProvider>
</React.StrictMode>,
Expand Down
5 changes: 1 addition & 4 deletions apps/shinkai-visor/src/components/settings/settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,7 @@ export const Settings = () => {
<SelectContent>
{agents?.map((agent) => (
<SelectItem key={agent.id} value={agent.id}>
{
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(agent.full_identity_name as any)?.subidentity_name
}
{agent.id}
</SelectItem>
))}
</SelectContent>
Expand Down
6 changes: 3 additions & 3 deletions apps/shinkai-visor/src/components/welcome/welcome.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,11 @@ export default function Welcome() {
rel="noreferrer"
target={'_blank'}
>
Terms of Service{' '}
</a>
Terms of Service
</a>{' '}
and{' '}
<a
className={'block text-blue-400 underline'}
className={'text-blue-400 underline'}
data-testid="privacy-policy-link"
href={'https://www.shinkai.com/privacy-policy'}
rel="noreferrer"
Expand Down
24 changes: 23 additions & 1 deletion apps/shinkai-visor/src/components/with-nav/with-nav.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,34 @@
import { useGetHealth } from '@shinkai_network/shinkai-node-state/lib/queries/getHealth/useGetHealth';
import { useToast } from '@shinkai_network/shinkai-ui';
import { cn } from '@shinkai_network/shinkai-ui/utils';
import { PropsWithChildren } from 'react';
import { PropsWithChildren, useEffect } from 'react';
import { useLocation } from 'react-router-dom';

import { useAuth } from '../../store/auth/auth';
import NavBar from '../nav/nav';

export const WithNav = (props: PropsWithChildren) => {
const location = useLocation();
const auth = useAuth((state) => state.auth);
const isInboxPage = location.pathname.includes('/inboxes/');
const { toast } = useToast();

const { nodeInfo, isSuccess, isFetching } = useGetHealth(
{ node_address: auth?.node_address ?? '' },
{ refetchInterval: 10000, enabled: !!auth },
);

useEffect(() => {
if (isSuccess && nodeInfo?.status !== 'ok') {
toast({
title: 'Node Unavailable',
description:
'Visor is having trouble connecting to your Shinkai Node. Your node may be offline, or your internet connection may be down.',
variant: 'destructive',
});
}
}, [isSuccess, nodeInfo?.status, isFetching, toast]);

return (
<div
className={cn(
Expand Down
23 changes: 23 additions & 0 deletions apps/shinkai-visor/src/theme/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,26 @@
@apply bg-gray-100;
}
}


/* prose styling for chat editor */
.prose :where(p):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
@apply my-2;
}
.prose-sm
:where(pre):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
@apply mt-2 border border-gray-700 bg-transparent;
}
.tiptap p.is-editor-empty:first-child::before {
content: attr(data-placeholder);
@apply pointer-events-none float-left h-0 text-gray-100;
}
.tiptap {
@apply min-h-[60px] max-w-full rounded-md border border-gray-200 bg-gray-400 px-3 py-2 text-sm shadow-sm placeholder:text-gray-80 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-gray-950 disabled:cursor-not-allowed disabled:opacity-50;
}
.tiptap[contenteditable='false'] {
@apply opacity-40;
}
.wmde-markdown pre {
@apply grid;
}
13 changes: 11 additions & 2 deletions libs/shinkai-node-state/src/lib/queries/getHealth/types.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
import { UndefinedInitialDataOptions } from '@tanstack/react-query/src/queryOptions';
import { QueryObserverOptions } from '@tanstack/react-query';

import { FunctionKey } from '../../constants';

export type GetHealthInput = {
node_address: string;
};
export type UseGetHealth = [FunctionKey.GET_HEALTH, GetHealthInput];
export type GetHealthOutput = {
is_pristine: boolean;
node_name: string;
status: string;
version: string;
};

export type Options = UndefinedInitialDataOptions<GetHealthOutput>;
export type Options = QueryObserverOptions<
GetHealthOutput,
Error,
GetHealthOutput,
GetHealthOutput,
UseGetHealth
>;
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { useQuery } from '@tanstack/react-query';

import { FunctionKey } from '../../constants';
import { getHealth } from '.';
import { GetHealthInput, GetHealthOutput, Options } from './types';
import { GetHealthInput, Options } from './types';

export const useGetHealth = (input: GetHealthInput, options?: Options) => {
const response = useQuery<GetHealthOutput>({
const response = useQuery({
queryKey: [FunctionKey.GET_HEALTH, input],
queryFn: async () => await getHealth(input),
...options,
Expand Down
4 changes: 2 additions & 2 deletions libs/shinkai-ui/src/components/markdown-preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ export const MarkdownPreview = ({
}: {
className?: string;
source?: string;
components?: Parameters<typeof ReactMarkdownPreview>[0]['components']
components?: Parameters<typeof ReactMarkdownPreview>[0]['components'];
}) => {
return (
<ReactMarkdownPreview
className={cn(
'wmde-markdown-var prose prose-gray prose-code:text-white prose-blockquote:text-gray-50 prose-blockquote:bg-gray-200',
'wmde-markdown-var prose prose-gray prose-code:text-white prose-blockquote:text-gray-50 prose-blockquote:bg-gray-200 prose-strong:text-white prose-headings:text-white',
className,
)}
components={components}
Expand Down
92 changes: 92 additions & 0 deletions libs/shinkai-ui/src/components/message-editor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { Placeholder } from '@tiptap/extension-placeholder';
import { EditorContent, Extension, useEditor } from '@tiptap/react';
import { StarterKit } from '@tiptap/starter-kit';
import { useEffect, useLayoutEffect, useRef } from 'react';
import * as React from 'react';
import { Markdown } from 'tiptap-markdown';

import { DotsLoader } from './dots-loader';

export const MessageEditor = ({
value,
onChange,
onSubmit,
setInitialValue,
disabled,
isLoading,
placeholder,
}: {
value: string;
onChange: (value: string) => void;
onSubmit: () => void;
setInitialValue?: string;
disabled?: boolean;
isLoading?: boolean;
placeholder?: string;
}) => {
// onSubmitRef is used to keep the latest onSubmit function
const onSubmitRef = useRef(onSubmit);
useLayoutEffect(() => {
onSubmitRef.current = onSubmit;
});

const editor = useEditor(
{
editorProps: {
attributes: {
class: 'prose prose-invert prose-sm mx-auto focus:outline-none',
},
},
extensions: [
StarterKit,
Placeholder.configure({
placeholder: placeholder ?? 'Enter message',
}),
Markdown,
Extension.create({
addKeyboardShortcuts() {
return {
Enter: () => {
onSubmitRef?.current?.();
return this.editor.commands.clearContent();
},
'Shift-Enter': ({ editor }) =>
editor.commands.first(({ commands }) => [
() => commands.newlineInCode(),
() => commands.splitListItem('listItem'),
() => commands.createParagraphNear(),
() => commands.liftEmptyBlock(),
() => commands.splitBlock(),
]),
};
},
}),
],
content: value,
autofocus: true,
onUpdate({ editor }) {
onChange(editor.storage.markdown.getMarkdown());
},
editable: !disabled,
},
[disabled],
);

useEffect(() => {
setInitialValue === undefined
? editor?.commands.setContent('')
: editor?.commands.setContent(value);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [setInitialValue]);

useEffect(() => {
if (value === '') editor?.commands.setContent('');
}, [value, editor]);

return (
<>
{isLoading ? <DotsLoader className="absolute left-4 top-6 z-50" /> : null}
<EditorContent editor={editor} />
</>
);
};
Loading

0 comments on commit 21e5022

Please sign in to comment.