From b02f7be41545ae65b2673da3fa7777e4b965f254 Mon Sep 17 00:00:00 2001 From: Alfredo Gallardo Date: Tue, 10 Oct 2023 08:47:10 -0500 Subject: [PATCH] - feature: ui improvements after rewrite (#35) * - fix: improved connect using healthcheck to shinkai-node * - fix: improved crxjs hmr * - feature: implemented toggle popup shortcut * - fix: added command label to action button * - feature: added agent workflow * - fix: inboxes improvments * - fix: wrap context when send to agent * - fix: lint errors with unknown react properties * - fix: removed hmr workaround --- .eslintrc.json | 4 +- apps/shinkai-visor/.eslintrc.json | 2 +- apps/shinkai-visor/public/manifest.json | 12 +- .../action-button/action-button.tsx | 21 +- .../src/components/add-agent/add-agent.tsx | 6 +- .../src/components/add-node/add-node.tsx | 32 +- .../src/components/create-job/create-job.tsx | 2 +- .../components/inbox-input/inbox-input.tsx | 1 + .../src/components/inbox/inbox.tsx | 20 +- .../src/components/inboxes/inboxes.tsx | 49 ++- apps/shinkai-visor/src/components/nav/nav.tsx | 4 +- .../popup-routing/popup-routing.tsx | 13 +- .../src/components/ui/command.tsx | 155 ++++++++++ .../src/components/ui/dialog.tsx | 119 ++++++++ .../src/components/with-nav/with-nav.tsx | 2 +- ...use-global-action-button-chrome-message.ts | 2 +- .../hooks/use-global-popup-chrome-message.ts | 4 +- apps/shinkai-visor/src/lang/en.json | 4 +- .../content-script-message-type.ts | 2 +- .../communication/content-script-message.ts | 2 +- .../communication/content-script-messages.ts | 10 +- .../service-worker/communication/message.ts | 6 +- .../src/service-worker/context-menu.ts | 2 +- .../src/service-worker/service-worker.ts | 3 +- .../src/service-worker/shortcuts.ts | 23 ++ package-lock.json | 289 ++++++++++++++++++ package.json | 2 + 27 files changed, 704 insertions(+), 87 deletions(-) create mode 100644 apps/shinkai-visor/src/components/ui/command.tsx create mode 100644 apps/shinkai-visor/src/components/ui/dialog.tsx create mode 100644 apps/shinkai-visor/src/service-worker/shortcuts.ts diff --git a/.eslintrc.json b/.eslintrc.json index 78a33fc1c..dfbe820e8 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -32,7 +32,9 @@ { "files": ["*.ts", "*.tsx"], "extends": ["plugin:@nx/typescript"], - "rules": {} + "rules": { + "react/no-unknown-property": ["error", { "ignore": ["cmdk-input-wrapper"] }] + } }, { "files": ["*.js", "*.jsx"], diff --git a/apps/shinkai-visor/.eslintrc.json b/apps/shinkai-visor/.eslintrc.json index a39ac5d05..5ac4de061 100644 --- a/apps/shinkai-visor/.eslintrc.json +++ b/apps/shinkai-visor/.eslintrc.json @@ -1,6 +1,6 @@ { "extends": ["plugin:@nx/react", "../../.eslintrc.json"], - "ignorePatterns": ["!**/*"], + "ignorePatterns": ["!**/*", "dist"], "overrides": [ { "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], diff --git a/apps/shinkai-visor/public/manifest.json b/apps/shinkai-visor/public/manifest.json index 161a00286..9d54d42f7 100644 --- a/apps/shinkai-visor/public/manifest.json +++ b/apps/shinkai-visor/public/manifest.json @@ -27,22 +27,14 @@ } ], "commands": { - "_execute_action": { - "suggested_key": { - "windows": "Ctrl+Shift+U", - "mac": "Ctrl+Shift+U", - "chromeos": "Ctrl+Shift+U", - "linux": "Ctrl+Shift+U" - } - }, - "command-launcher": { + "toggle-popup": { "suggested_key": { "windows": "Ctrl+Comma", "mac": "Command+Comma", "chromeos": "Ctrl+Comma", "linux": "Ctrl+Comma" }, - "description": "UV command launcher" + "description": "Open/Close Shinkai popup" } }, "permissions": ["storage", "contextMenus"], diff --git a/apps/shinkai-visor/src/components/action-button/action-button.tsx b/apps/shinkai-visor/src/components/action-button/action-button.tsx index 53418b508..a4b969141 100644 --- a/apps/shinkai-visor/src/components/action-button/action-button.tsx +++ b/apps/shinkai-visor/src/components/action-button/action-button.tsx @@ -6,6 +6,7 @@ import { Provider } from 'react-redux'; import { PersistGate } from 'redux-persist/integration/react'; import shinkaiLogo from '../../assets/icons/shinkai-min.svg'; +import { cn } from '../../helpers/cn-utils'; import { srcUrlResolver } from '../../helpers/src-url-resolver'; import { useGlobalActionButtonChromeMessage } from '../../hooks/use-global-action-button-chrome-message'; import { langMessages, locale } from '../../lang/intl'; @@ -32,25 +33,29 @@ export const ActionButton = () => { const togglePopupVisibility = () => { sendContentScriptMessage({ type: ContentScriptMessageType.TogglePopupVisibility, - data: !popupVisibility, }); }; return ( -
togglePopupVisibility()}> +
togglePopupVisibility()} + > shinkai-app-logo + ⌘ + ,
); }; @@ -63,11 +68,11 @@ root.render( -
+
- , + ); diff --git a/apps/shinkai-visor/src/components/add-agent/add-agent.tsx b/apps/shinkai-visor/src/components/add-agent/add-agent.tsx index e8ed3870e..312595570 100644 --- a/apps/shinkai-visor/src/components/add-agent/add-agent.tsx +++ b/apps/shinkai-visor/src/components/add-agent/add-agent.tsx @@ -55,11 +55,9 @@ export const AddAgent = () => { const { mutateAsync: createAgent, isLoading, - isError, - error, } = useCreateAgent({ - onSuccess: () => { - history.replace('/agents'); + onSuccess: (data) => { + history.replace({ pathname: '/inboxes/create-job' }); }, }); diff --git a/apps/shinkai-visor/src/components/add-node/add-node.tsx b/apps/shinkai-visor/src/components/add-node/add-node.tsx index ee5e1a50c..870488c2c 100644 --- a/apps/shinkai-visor/src/components/add-node/add-node.tsx +++ b/apps/shinkai-visor/src/components/add-node/add-node.tsx @@ -28,15 +28,15 @@ import { import { Input } from '../ui/input'; const formSchema = z.object({ - registrationCode: z.string().nonempty(), + registrationCode: z.string().optional(), registrationName: z.string().nonempty(), permissionType: z.enum(['admin']), identityType: z.enum(['device']), profile: z.enum(['main']), nodeAddress: z.string().url(), shinkaiIdentity: z.string().nonempty(), - nodeEncryptionPublicKey: z.string().nonempty(), - nodeSignaturePublicKey: z.string().nonempty(), + nodeEncryptionPublicKey: z.string().optional(), + nodeSignaturePublicKey: z.string().optional(), profileEncryptionPublicKey: z.string().nonempty(), profileSignaturePublicKey: z.string().nonempty(), myDeviceEncryptionPublicKey: z.string().nonempty(), @@ -66,6 +66,9 @@ enum AddNodeSteps { export const AddNode = () => { const history = useHistory(); const setAuth = useAuth((state) => state.setAuth); + const DEFAULT_NODE_ADDRESS = 'http://127.0.0.1:9550'; + // TODO: This value should be obtained from node + const DEFAULT_SHINKAI_IDENTITY = '@@node1.shinkai'; const form = useForm({ resolver: zodResolver(formSchema), defaultValues: { @@ -100,8 +103,8 @@ export const AddNode = () => { permission_type: values.permissionType, node_address: values.nodeAddress, shinkai_identity: values.shinkaiIdentity, - node_signature_pk: response.data?.identity_public_key ?? values.nodeSignaturePublicKey, - node_encryption_pk: response.data?.encryption_public_key ?? values.nodeEncryptionPublicKey, + node_signature_pk: response.data?.identity_public_key ?? values.nodeSignaturePublicKey ?? '', + node_encryption_pk: response.data?.encryption_public_key ?? values.nodeEncryptionPublicKey ?? '', registration_name: values.registrationName, my_device_identity_pk: values.myDeviceIdentityPublicKey, my_device_identity_sk: values.myDeviceIdentitySharedKey, @@ -204,15 +207,14 @@ export const AddNode = () => { }; const connect = (values: FormType) => { - console.log('values', values); submitRegistration({ - registration_code: values.registrationCode, + registration_code: values.registrationCode ?? '', profile: values.profile, identity_type: values.identityType, permission_type: values.permissionType, node_address: values.nodeAddress, shinkai_identity: values.shinkaiIdentity, - node_encryption_pk: values.nodeEncryptionPublicKey, + node_encryption_pk: values.nodeEncryptionPublicKey ?? '', registration_name: values.registrationName, my_device_identity_sk: values.myDeviceIdentitySharedKey, my_device_encryption_sk: values.myDeviceEncryptionSharedKey, @@ -245,8 +247,22 @@ export const AddNode = () => { ); }, [form]); + useEffect(() => { + fetch(`${DEFAULT_NODE_ADDRESS}/v1/shinkai_health`) + .then((response) => response.json()) + .then((data) => { + if (data.status === 'ok') { + form.setValue('nodeAddress', DEFAULT_NODE_ADDRESS); + form.setValue('shinkaiIdentity', DEFAULT_SHINKAI_IDENTITY); + setCurrentStep(AddNodeSteps.Connect) + } + }) + .catch((error) => console.error('error polling', error)); + }, [form]); + return (
+ Connect
{currentStep === AddNodeSteps.ScanQR && (
diff --git a/apps/shinkai-visor/src/components/create-job/create-job.tsx b/apps/shinkai-visor/src/components/create-job/create-job.tsx index 76dad3f1d..82e96f144 100644 --- a/apps/shinkai-visor/src/components/create-job/create-job.tsx +++ b/apps/shinkai-visor/src/components/create-job/create-job.tsx @@ -66,7 +66,7 @@ export const CreateJob = () => { if (!auth) return; let content = values.content; if (query.has('context')) { - content = `${values.content} - ${query.get('context')}`; + content = `${values.content} - \`\`\`${query.get('context')}\`\`\``; } createJob({ shinkaiIdentity: auth.shinkai_identity, diff --git a/apps/shinkai-visor/src/components/inbox-input/inbox-input.tsx b/apps/shinkai-visor/src/components/inbox-input/inbox-input.tsx index 9ffd1805f..22adf4730 100644 --- a/apps/shinkai-visor/src/components/inbox-input/inbox-input.tsx +++ b/apps/shinkai-visor/src/components/inbox-input/inbox-input.tsx @@ -56,6 +56,7 @@ export const InboxInput = (props: InboxInputProps) => { { const getAvatar = (message: ShinkaiMessage) => { return isLocalMessage( message, - auth?.profile || '', - auth?.registration_name || '' + auth?.shinkai_identity || '', + auth?.profile || '' ) ? 'https://ui-avatars.com/api/?name=Me&background=FE6162&color=fff' : 'https://ui-avatars.com/api/?name=O&background=363636&color=fff'; @@ -174,20 +174,6 @@ export const Inbox = () => { ))} {isChatConversationSuccess && data?.pages?.map((group, index) => ( - //
- // {getMessageContent(message)} - //
{Object.entries(groupMessagesByDate(group)).map( ([date, messages]) => { @@ -195,7 +181,7 @@ export const Inbox = () => {
diff --git a/apps/shinkai-visor/src/components/inboxes/inboxes.tsx b/apps/shinkai-visor/src/components/inboxes/inboxes.tsx index 56c0c5657..0b9055bb9 100644 --- a/apps/shinkai-visor/src/components/inboxes/inboxes.tsx +++ b/apps/shinkai-visor/src/components/inboxes/inboxes.tsx @@ -1,9 +1,15 @@ import './inboxes.css'; import { useGetInboxes } from '@shinkai_network/shinkai-node-state/lib/queries/getInboxes/useGetInboxes'; +import { Bot } from 'lucide-react'; +import { Fragment } from 'react'; +import { FormattedMessage } from 'react-intl'; import { useHistory } from 'react-router-dom'; +import logo from '../../../src/assets/icons/shinkai-min.svg'; +import { srcUrlResolver } from '../../helpers/src-url-resolver'; import { useAuth } from '../../store/auth/auth'; +import { Button } from '../ui/button'; import { ScrollArea } from '../ui/scroll-area'; import { Separator } from '../ui/separator'; @@ -29,19 +35,38 @@ export const Inboxes = () => { return (
- - {inboxIds?.map((inboxId) => ( -
-
navigateToInbox(inboxId)} - > - {inboxId} -
- + {!inboxIds?.length ? ( +
+
+ shinkai logo
- ))} - +

+ +

+

+ +

+ + +
+ ) : ( + + {inboxIds?.map((inboxId) => ( + + + + + ))} + + )}
); }; diff --git a/apps/shinkai-visor/src/components/nav/nav.tsx b/apps/shinkai-visor/src/components/nav/nav.tsx index b461be4db..e06127abd 100644 --- a/apps/shinkai-visor/src/components/nav/nav.tsx +++ b/apps/shinkai-visor/src/components/nav/nav.tsx @@ -50,10 +50,10 @@ export default function NavBar() { history.replace('/inboxes'); break; case MenuOption.CreateInbox: - history.replace('/inboxes/create'); + history.replace('/inboxes/create-inbox'); break; case MenuOption.CreateJob: - history.replace('/jobs/create'); + history.replace('/inboxes/create-job'); break; case MenuOption.Agents: history.replace('/agents'); diff --git a/apps/shinkai-visor/src/components/popup-routing/popup-routing.tsx b/apps/shinkai-visor/src/components/popup-routing/popup-routing.tsx index ec8d5e93e..d40ac4193 100644 --- a/apps/shinkai-visor/src/components/popup-routing/popup-routing.tsx +++ b/apps/shinkai-visor/src/components/popup-routing/popup-routing.tsx @@ -58,9 +58,12 @@ export const PopupRouting = () => { - + + + + @@ -80,14 +83,6 @@ export const PopupRouting = () => { - - - - - - - - diff --git a/apps/shinkai-visor/src/components/ui/command.tsx b/apps/shinkai-visor/src/components/ui/command.tsx new file mode 100644 index 000000000..ff79bdef6 --- /dev/null +++ b/apps/shinkai-visor/src/components/ui/command.tsx @@ -0,0 +1,155 @@ +"use client" + +import { DialogProps } from "@radix-ui/react-dialog" +import { Command as CommandPrimitive } from "cmdk" +import { Search } from "lucide-react" +import * as React from "react" + +import { cn } from "../../helpers/cn-utils" +import { Dialog, DialogContent } from "./dialog" + +const Command = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +Command.displayName = CommandPrimitive.displayName + +type CommandDialogProps = DialogProps + +const CommandDialog = ({ children, ...props }: CommandDialogProps) => { + return ( + + + + {children} + + + + ) +} + +const CommandInput = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( +
+ + +
+)) + +CommandInput.displayName = CommandPrimitive.Input.displayName + +const CommandList = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) + +CommandList.displayName = CommandPrimitive.List.displayName + +const CommandEmpty = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>((props, ref) => ( + +)) + +CommandEmpty.displayName = CommandPrimitive.Empty.displayName + +const CommandGroup = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) + +CommandGroup.displayName = CommandPrimitive.Group.displayName + +const CommandSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +CommandSeparator.displayName = CommandPrimitive.Separator.displayName + +const CommandItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) + +CommandItem.displayName = CommandPrimitive.Item.displayName + +const CommandShortcut = ({ + className, + ...props +}: React.HTMLAttributes) => { + return ( + + ) +} +CommandShortcut.displayName = "CommandShortcut" + +export { + Command, + CommandDialog, + CommandInput, + CommandList, + CommandEmpty, + CommandGroup, + CommandItem, + CommandShortcut, + CommandSeparator, +} diff --git a/apps/shinkai-visor/src/components/ui/dialog.tsx b/apps/shinkai-visor/src/components/ui/dialog.tsx new file mode 100644 index 000000000..a62da8692 --- /dev/null +++ b/apps/shinkai-visor/src/components/ui/dialog.tsx @@ -0,0 +1,119 @@ +"use client" + +import * as DialogPrimitive from "@radix-ui/react-dialog" +import { X } from "lucide-react" +import * as React from "react" + +import { cn } from "../../helpers/cn-utils" + +const Dialog = DialogPrimitive.Root + +const DialogTrigger = DialogPrimitive.Trigger + +const DialogPortal = DialogPrimitive.Portal + +const DialogOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogOverlay.displayName = DialogPrimitive.Overlay.displayName + +const DialogContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + {children} + + + Close + + + +)) +DialogContent.displayName = DialogPrimitive.Content.displayName + +const DialogHeader = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+) +DialogHeader.displayName = "DialogHeader" + +const DialogFooter = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+) +DialogFooter.displayName = "DialogFooter" + +const DialogTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogTitle.displayName = DialogPrimitive.Title.displayName + +const DialogDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogDescription.displayName = DialogPrimitive.Description.displayName + +export { + Dialog, + DialogPortal, + DialogOverlay, + DialogTrigger, + DialogContent, + DialogHeader, + DialogFooter, + DialogTitle, + DialogDescription, +} diff --git a/apps/shinkai-visor/src/components/with-nav/with-nav.tsx b/apps/shinkai-visor/src/components/with-nav/with-nav.tsx index e27d51a2e..4d4865b67 100644 --- a/apps/shinkai-visor/src/components/with-nav/with-nav.tsx +++ b/apps/shinkai-visor/src/components/with-nav/with-nav.tsx @@ -7,7 +7,7 @@ export const WithNav = (props: PropsWithChildren) => { return (
- + {/* */}
{props.children}
); diff --git a/apps/shinkai-visor/src/hooks/use-global-action-button-chrome-message.ts b/apps/shinkai-visor/src/hooks/use-global-action-button-chrome-message.ts index b0ae5fa1d..fc59b6350 100644 --- a/apps/shinkai-visor/src/hooks/use-global-action-button-chrome-message.ts +++ b/apps/shinkai-visor/src/hooks/use-global-action-button-chrome-message.ts @@ -12,7 +12,7 @@ export const useGlobalActionButtonChromeMessage = () => { sendContentScriptMessage({ type: ContentScriptMessageType.TogglePopupVisibility, data: true }); } else if (message.type === ServiceWorkerMessageType.ContentScript) { if (message.data.type === ContentScriptMessageType.TogglePopupVisibility) { - setPopupVisibility(message.data.data); + setPopupVisibility(message.data.data !== undefined ? message.data.data : !popupVisibility); } } }); diff --git a/apps/shinkai-visor/src/hooks/use-global-popup-chrome-message.ts b/apps/shinkai-visor/src/hooks/use-global-popup-chrome-message.ts index 38a242f70..ae38c80e5 100644 --- a/apps/shinkai-visor/src/hooks/use-global-popup-chrome-message.ts +++ b/apps/shinkai-visor/src/hooks/use-global-popup-chrome-message.ts @@ -11,10 +11,10 @@ export const useGlobalPopupChromeMessage = () => { useChromeMessage((message, sender) => { if (message.type === ServiceWorkerMessageType.SendToAgent) { const params = new URLSearchParams({ context: message?.data?.textContent }); - history.replace({ pathname: '/jobs/create', search: params.toString() }); + history.replace({ pathname: '/inboxes/create-job', search: params.toString() }); } else if (message.type === ServiceWorkerMessageType.ContentScript) { if (message.data.type === ContentScriptMessageType.TogglePopupVisibility) { - setPopupVisibility(message.data.data); + setPopupVisibility(message.data.data !== undefined ? message.data.data : !popupVisibility); } } }); diff --git a/apps/shinkai-visor/src/lang/en.json b/apps/shinkai-visor/src/lang/en.json index b09914b7e..0d3ba3d2c 100644 --- a/apps/shinkai-visor/src/lang/en.json +++ b/apps/shinkai-visor/src/lang/en.json @@ -45,5 +45,7 @@ "menu": "Menu", "account.one": "Account", "account.other": "Accounts", - "all-messages-loaded": "All messages has been loaded 🎈" + "all-messages-loaded": "All messages has been loaded 🎈", + "ask-to-shinkai-ai": "Ask Shinkai AI", + "ask-to-shinkai-ai-example": "Try \"How to make a HTTP request in Javascript\" or \"Give me the top 10 rock music in the 80s\"" } diff --git a/apps/shinkai-visor/src/service-worker/communication/content-script-message-type.ts b/apps/shinkai-visor/src/service-worker/communication/content-script-message-type.ts index b508baadd..85f1226e8 100644 --- a/apps/shinkai-visor/src/service-worker/communication/content-script-message-type.ts +++ b/apps/shinkai-visor/src/service-worker/communication/content-script-message-type.ts @@ -1,3 +1,3 @@ export enum ContentScriptMessageType { - TogglePopupVisibility = 'toggle-popup-visibility', + TogglePopupVisibility = 'toggle-popup-visibility' } diff --git a/apps/shinkai-visor/src/service-worker/communication/content-script-message.ts b/apps/shinkai-visor/src/service-worker/communication/content-script-message.ts index 7447962a7..0cef278ae 100644 --- a/apps/shinkai-visor/src/service-worker/communication/content-script-message.ts +++ b/apps/shinkai-visor/src/service-worker/communication/content-script-message.ts @@ -1,4 +1,4 @@ import { ContentScriptMessageType } from "./content-script-message-type"; export type ContentScriptMessage = - { type: ContentScriptMessageType.TogglePopupVisibility, data: boolean }; + { type: ContentScriptMessageType.TogglePopupVisibility, data?: boolean }; diff --git a/apps/shinkai-visor/src/service-worker/communication/content-script-messages.ts b/apps/shinkai-visor/src/service-worker/communication/content-script-messages.ts index ab06cf609..1ce57ace0 100644 --- a/apps/shinkai-visor/src/service-worker/communication/content-script-messages.ts +++ b/apps/shinkai-visor/src/service-worker/communication/content-script-messages.ts @@ -3,7 +3,11 @@ import { ServiceWorkerMessageType } from "./service-worker-message-type"; import { ServiceWorkerMessage } from "./service-worker-messages"; -export const sendContentScriptMessage = (message: ContentScriptMessage) => { - const contentScriptMessage: ServiceWorkerMessage = { type: ServiceWorkerMessageType.ContentScript, data: message } as any; - chrome.runtime.sendMessage(contentScriptMessage); +export const sendContentScriptMessage = (message: ContentScriptMessage, tabId?: number) => { + const contentScriptMessage: ServiceWorkerMessage = { type: ServiceWorkerMessageType.ContentScript, data: message }; + if (tabId) { + chrome.tabs.sendMessage(tabId, contentScriptMessage); + } else { + chrome.runtime.sendMessage(contentScriptMessage); + } } diff --git a/apps/shinkai-visor/src/service-worker/communication/message.ts b/apps/shinkai-visor/src/service-worker/communication/message.ts index b4648ab9d..9567534fd 100644 --- a/apps/shinkai-visor/src/service-worker/communication/message.ts +++ b/apps/shinkai-visor/src/service-worker/communication/message.ts @@ -1,6 +1,8 @@ +import { sendContentScriptMessage } from "./content-script-messages"; import { ServiceWorkerMessageType } from "./service-worker-message-type"; +import { ServiceWorkerMessage } from "./service-worker-messages"; -chrome.runtime.onMessage.addListener((message, sender) => { +chrome.runtime.onMessage.addListener((message: ServiceWorkerMessage, sender) => { console.log('sw onMessage', message, sender); // It allows inter content scripts communication. // SW act as a reverse proxy between content scripts in the same tab id @@ -9,6 +11,6 @@ chrome.runtime.onMessage.addListener((message, sender) => { return; } console.log('sw onMessage - forwarding message to tab', message, sender); - chrome.tabs.sendMessage(sender?.tab?.id, message); + sendContentScriptMessage(message.data, sender?.tab?.id); } }); diff --git a/apps/shinkai-visor/src/service-worker/context-menu.ts b/apps/shinkai-visor/src/service-worker/context-menu.ts index 01ab20300..192f9912d 100644 --- a/apps/shinkai-visor/src/service-worker/context-menu.ts +++ b/apps/shinkai-visor/src/service-worker/context-menu.ts @@ -47,7 +47,7 @@ const registerMenu = () => { ); chrome.contextMenus.create({ id: ContextMenu.SendToAgent, - title: 'Send to agent', + title: 'Ask to agent', contexts: ['all'] }); } diff --git a/apps/shinkai-visor/src/service-worker/service-worker.ts b/apps/shinkai-visor/src/service-worker/service-worker.ts index daea44ec5..1a106b900 100644 --- a/apps/shinkai-visor/src/service-worker/service-worker.ts +++ b/apps/shinkai-visor/src/service-worker/service-worker.ts @@ -1,2 +1,3 @@ import './context-menu'; -import './communication/message'; \ No newline at end of file +import './communication/message'; +import './shortcuts'; diff --git a/apps/shinkai-visor/src/service-worker/shortcuts.ts b/apps/shinkai-visor/src/service-worker/shortcuts.ts new file mode 100644 index 000000000..9dcf891d7 --- /dev/null +++ b/apps/shinkai-visor/src/service-worker/shortcuts.ts @@ -0,0 +1,23 @@ +import { ContentScriptMessageType } from "./communication/content-script-message-type"; +import { sendContentScriptMessage } from "./communication/content-script-messages"; + +export enum ServiceWorkerShortcut { + TogglePopup = 'toggle-popup' +}; + +const handleTogglePopup = (tabId: number) => { + sendContentScriptMessage({ type: ContentScriptMessageType.TogglePopupVisibility }, tabId); +} +chrome.commands.onCommand.addListener((command, tab) => { + console.log('command', command, tab); + switch (command) { + case ServiceWorkerShortcut.TogglePopup: + if (!tab.id) { + return; + } + handleTogglePopup(tab.id); + break; + default: + break; + } +}); diff --git a/package-lock.json b/package-lock.json index 34ff7a5cf..7d3efa81c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "@noble/ed25519": "^2.0.0", "@noble/hashes": "^1.3.1", "@radix-ui/react-avatar": "^1.0.4", + "@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-dropdown-menu": "^2.0.6", "@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-label": "^2.0.2", @@ -46,6 +47,7 @@ "class-variance-authority": "^0.7.0", "classnames": "^2.3.1", "clsx": "^2.0.0", + "cmdk": "^0.2.0", "crx": "^5.0.1", "crypto-js": "^4.1.1", "curve25519-js": "^0.0.4", @@ -5534,6 +5536,42 @@ } } }, + "node_modules/@radix-ui/react-dialog": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.0.5.tgz", + "integrity": "sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-context": "1.0.1", + "@radix-ui/react-dismissable-layer": "1.0.5", + "@radix-ui/react-focus-guards": "1.0.1", + "@radix-ui/react-focus-scope": "1.0.4", + "@radix-ui/react-id": "1.0.1", + "@radix-ui/react-portal": "1.0.4", + "@radix-ui/react-presence": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-slot": "1.0.2", + "@radix-ui/react-use-controllable-state": "1.0.1", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.5" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-direction": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.0.1.tgz", @@ -10510,6 +10548,252 @@ "node": ">=6" } }, + "node_modules/cmdk": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/cmdk/-/cmdk-0.2.0.tgz", + "integrity": "sha512-JQpKvEOb86SnvMZbYaFKYhvzFntWBeSZdyii0rZPhKJj9uwJBxu4DaVYDrRN7r3mPop56oPhRw+JYWTKs66TYw==", + "dependencies": { + "@radix-ui/react-dialog": "1.0.0", + "command-score": "0.1.2" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/cmdk/node_modules/@radix-ui/primitive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.0.tgz", + "integrity": "sha512-3e7rn8FDMin4CgeL7Z/49smCA3rFYY3Ha2rUQ7HRWFadS5iCRw08ZgVT1LaNTCNqgvrUiyczLflrVrF0SRQtNA==", + "dependencies": { + "@babel/runtime": "^7.13.10" + } + }, + "node_modules/cmdk/node_modules/@radix-ui/react-compose-refs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.0.tgz", + "integrity": "sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA==", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/cmdk/node_modules/@radix-ui/react-context": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.0.0.tgz", + "integrity": "sha512-1pVM9RfOQ+n/N5PJK33kRSKsr1glNxomxONs5c49MliinBY6Yw2Q995qfBUUo0/Mbg05B/sGA0gkgPI7kmSHBg==", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/cmdk/node_modules/@radix-ui/react-dialog": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.0.0.tgz", + "integrity": "sha512-Yn9YU+QlHYLWwV1XfKiqnGVpWYWk6MeBVM6x/bcoyPvxgjQGoeT35482viLPctTMWoMw0PoHgqfSox7Ig+957Q==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-dismissable-layer": "1.0.0", + "@radix-ui/react-focus-guards": "1.0.0", + "@radix-ui/react-focus-scope": "1.0.0", + "@radix-ui/react-id": "1.0.0", + "@radix-ui/react-portal": "1.0.0", + "@radix-ui/react-presence": "1.0.0", + "@radix-ui/react-primitive": "1.0.0", + "@radix-ui/react-slot": "1.0.0", + "@radix-ui/react-use-controllable-state": "1.0.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.4" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/cmdk/node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.0.tgz", + "integrity": "sha512-n7kDRfx+LB1zLueRDvZ1Pd0bxdJWDUZNQ/GWoxDn2prnuJKRdxsjulejX/ePkOsLi2tTm6P24mDqlMSgQpsT6g==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-primitive": "1.0.0", + "@radix-ui/react-use-callback-ref": "1.0.0", + "@radix-ui/react-use-escape-keydown": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/cmdk/node_modules/@radix-ui/react-focus-guards": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.0.tgz", + "integrity": "sha512-UagjDk4ijOAnGu4WMUPj9ahi7/zJJqNZ9ZAiGPp7waUWJO0O1aWXi/udPphI0IUjvrhBsZJGSN66dR2dsueLWQ==", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/cmdk/node_modules/@radix-ui/react-focus-scope": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.0.tgz", + "integrity": "sha512-C4SWtsULLGf/2L4oGeIHlvWQx7Rf+7cX/vKOAD2dXW0A1b5QXwi3wWeaEgW+wn+SEVrraMUk05vLU9fZZz5HbQ==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-primitive": "1.0.0", + "@radix-ui/react-use-callback-ref": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/cmdk/node_modules/@radix-ui/react-id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.0.tgz", + "integrity": "sha512-Q6iAB/U7Tq3NTolBBQbHTgclPmGWE3OlktGGqrClPozSw4vkQ1DfQAOtzgRPecKsMdJINE05iaoDUG8tRzCBjw==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-layout-effect": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/cmdk/node_modules/@radix-ui/react-portal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.0.0.tgz", + "integrity": "sha512-a8qyFO/Xb99d8wQdu4o7qnigNjTPG123uADNecz0eX4usnQEj7o+cG4ZX4zkqq98NYekT7UoEQIjxBNWIFuqTA==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/cmdk/node_modules/@radix-ui/react-presence": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.0.0.tgz", + "integrity": "sha512-A+6XEvN01NfVWiKu38ybawfHsBjWum42MRPnEuqPsBZ4eV7e/7K321B5VgYMPv3Xx5An6o1/l9ZuDBgmcmWK3w==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-use-layout-effect": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/cmdk/node_modules/@radix-ui/react-primitive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.0.tgz", + "integrity": "sha512-EyXe6mnRlHZ8b6f4ilTDrXmkLShICIuOTTj0GX4w1rp+wSxf3+TD05u1UOITC8VsJ2a9nwHvdXtOXEOl0Cw/zQ==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-slot": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/cmdk/node_modules/@radix-ui/react-slot": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.0.tgz", + "integrity": "sha512-3mrKauI/tWXo1Ll+gN5dHcxDPdm/Df1ufcDLCecn+pnCIVcdWE7CujXo8QaXOWRJyZyQWWbpB8eFwHzWXlv5mQ==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/cmdk/node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.0.tgz", + "integrity": "sha512-GZtyzoHz95Rhs6S63D2t/eqvdFCm7I+yHMLVQheKM7nBD8mbZIt+ct1jz4536MDnaOGKIxynJ8eHTkVGVVkoTg==", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/cmdk/node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.0.tgz", + "integrity": "sha512-FohDoZvk3mEXh9AWAVyRTYR4Sq7/gavuofglmiXB2g1aKyboUD4YtgWxKj8O5n+Uak52gXQ4wKz5IFST4vtJHg==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-callback-ref": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/cmdk/node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.0.tgz", + "integrity": "sha512-JwfBCUIfhXRxKExgIqGa4CQsiMemo1Xt0W/B4ei3fpzpvPENKpMKQ8mZSB6Acj3ebrAEgi2xiQvcI1PAAodvyg==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-callback-ref": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/cmdk/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.0.tgz", + "integrity": "sha512-6Tpkq+R6LOlmQb1R5NNETLG0B4YP0wc+klfXafpUCj6JGyaUc8il7/kUZ7m59rGbXGczE9Bs+iz2qloqsZBduQ==", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/cmdk/node_modules/react-remove-scroll": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.4.tgz", + "integrity": "sha512-xGVKJJr0SJGQVirVFAUZ2k1QLyO6m+2fy0l8Qawbp5Jgrv3DeLalrfMNBFSlmz5kriGGzsVBtGVnf4pTKIhhWA==", + "dependencies": { + "react-remove-scroll-bar": "^2.3.3", + "react-style-singleton": "^2.2.1", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.0", + "use-sidecar": "^1.1.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/co": { "version": "4.6.0", "dev": true, @@ -10584,6 +10868,11 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/command-score": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/command-score/-/command-score-0.1.2.tgz", + "integrity": "sha512-VtDvQpIJBvBatnONUsPzXYFVKQQAhuf3XTNOAsdBxCNO/QCtUUd8LSgjn0GVarBkCad6aJCZfXgrjYbl/KRr7w==" + }, "node_modules/commander": { "version": "7.2.0", "dev": true, diff --git a/package.json b/package.json index c1aa5c630..dd9f91bb3 100644 --- a/package.json +++ b/package.json @@ -99,6 +99,7 @@ "@noble/ed25519": "^2.0.0", "@noble/hashes": "^1.3.1", "@radix-ui/react-avatar": "^1.0.4", + "@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-dropdown-menu": "^2.0.6", "@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-label": "^2.0.2", @@ -121,6 +122,7 @@ "class-variance-authority": "^0.7.0", "classnames": "^2.3.1", "clsx": "^2.0.0", + "cmdk": "^0.2.0", "crx": "^5.0.1", "crypto-js": "^4.1.1", "curve25519-js": "^0.0.4",