2025-06-26 18:40:33 +08:00
|
|
|
import { SearchExtensionItem } from "@/components/Search/ExtensionStore";
|
2025-10-19 19:13:44 +08:00
|
|
|
import {
|
|
|
|
|
ExtensionPermission,
|
|
|
|
|
ViewExtensionUISettings,
|
|
|
|
|
} from "@/components/Settings/Extensions";
|
2025-01-21 19:37:15 +08:00
|
|
|
import { create } from "zustand";
|
|
|
|
|
import { persist } from "zustand/middleware";
|
|
|
|
|
|
2025-10-22 10:08:00 +08:00
|
|
|
export type ViewExtensionOpened = [
|
2025-11-13 19:50:32 +08:00
|
|
|
// Extension name
|
|
|
|
|
string,
|
|
|
|
|
// An absolute path to the extension icon or a font code.
|
|
|
|
|
string,
|
|
|
|
|
// HTML file URL
|
2025-10-22 10:08:00 +08:00
|
|
|
string,
|
|
|
|
|
ExtensionPermission | null,
|
|
|
|
|
ViewExtensionUISettings | null,
|
|
|
|
|
];
|
2025-10-19 19:13:44 +08:00
|
|
|
|
2025-01-21 19:37:15 +08:00
|
|
|
export type ISearchStore = {
|
|
|
|
|
sourceData: any;
|
|
|
|
|
setSourceData: (sourceData: any) => void;
|
2025-02-26 16:47:46 +08:00
|
|
|
sourceDataIds: string[];
|
|
|
|
|
setSourceDataIds: (prevSourceDataId: string[]) => void;
|
2025-04-24 19:00:16 +08:00
|
|
|
MCPIds: string[];
|
|
|
|
|
setMCPIds: (prevSourceDataId: string[]) => void;
|
2025-02-27 12:07:58 +08:00
|
|
|
visibleContextMenu: boolean;
|
|
|
|
|
setVisibleContextMenu: (visibleContextMenu: boolean) => void;
|
2025-02-27 16:02:09 +08:00
|
|
|
selectedSearchContent?: Record<string, any>;
|
|
|
|
|
setSelectedSearchContent: (
|
|
|
|
|
selectedSearchContent?: Record<string, any>
|
|
|
|
|
) => void;
|
2025-05-23 18:14:41 +08:00
|
|
|
goAskAi: boolean;
|
|
|
|
|
setGoAskAi: (goAskAi: boolean) => void;
|
|
|
|
|
askAiMessage: string;
|
|
|
|
|
setAskAiMessage: (askAiMessage: string) => void;
|
|
|
|
|
askAiSessionId?: string;
|
|
|
|
|
setAskAiSessionId: (askAiSessionId?: string) => void;
|
|
|
|
|
selectedAssistant?: any;
|
|
|
|
|
setSelectedAssistant: (selectedAssistant?: any) => void;
|
2025-05-26 10:56:29 +08:00
|
|
|
askAiServerId?: string;
|
|
|
|
|
setAskAiServerId: (askAiServerId?: string) => void;
|
2025-05-30 17:18:52 +08:00
|
|
|
enabledAiOverview: boolean;
|
|
|
|
|
setEnabledAiOverview: (enabledAiOverview: boolean) => void;
|
|
|
|
|
askAiAssistantId?: string;
|
|
|
|
|
setAskAiAssistantId: (askAiAssistantId?: string) => void;
|
2025-12-05 15:32:57 +08:00
|
|
|
targetServerId?: string;
|
|
|
|
|
setTargetServerId: (targetServerId?: string) => void;
|
2025-11-27 10:12:49 +08:00
|
|
|
targetAssistantId?: string;
|
|
|
|
|
setTargetAssistantId: (targetAssistantId?: string) => void;
|
2025-06-26 18:40:33 +08:00
|
|
|
visibleExtensionStore: boolean;
|
|
|
|
|
setVisibleExtensionStore: (visibleExtensionStore: boolean) => void;
|
|
|
|
|
searchValue: string;
|
|
|
|
|
setSearchValue: (searchValue: string) => void;
|
|
|
|
|
selectedExtension?: SearchExtensionItem;
|
|
|
|
|
setSelectedExtension: (selectedExtension?: SearchExtensionItem) => void;
|
|
|
|
|
installingExtensions: string[];
|
|
|
|
|
setInstallingExtensions: (installingExtensions: string[]) => void;
|
|
|
|
|
uninstallingExtensions: string[];
|
|
|
|
|
setUninstallingExtensions: (uninstallingExtensions: string[]) => void;
|
|
|
|
|
visibleExtensionDetail: boolean;
|
|
|
|
|
setVisibleExtensionDetail: (visibleExtensionDetail: boolean) => void;
|
feat: new extension type View (#894)
This commit introduces a new extension type View, which enables developers
to implement extensions with GUI. It is implemented using iframe, developers
can specify the path to the HTML file in the `Extension.page` field, then
Coco will load and render that page when the extension gets opened.
coco-api
We provide a TypeScript library [1] that will contain the APIs developers
need to make the experience better.
We start from file system APIs. Since the embedded HTML page will be loaded
by WebView, which has no access to the local file system, we provide APIs
to bridge that gap. Currently, `fs:read_dir()` is the only API we implemented, more
will come soon.
Permission
As View extensions run user-provided code, we introduce a permision
mechanism to sandbox the code. Developers must manually specify the
permission their extension needs in the "plugin.json" file, e,g.:
"permissions": {
"fs": [
{ "path": "/Users/foo/Downloads", "access": ["read", "write"] },
{ "path": "/Users/foo/Documents", "access": ["read"] }
],
"http": [
{ "host": "api.github.com" }
],
"api": ["fs:read_dir"]
}
Currently, both fs and api permissions are implemented. Permission checks
apply only to View extensions for now; Command extensions will support
them in the future.
[1]: https://github.com/infinilabs/coco-api
2025-09-25 11:12:29 +08:00
|
|
|
|
|
|
|
|
// When we open a View extension, we set this to a non-null value.
|
2025-10-22 10:08:00 +08:00
|
|
|
viewExtensionOpened?: ViewExtensionOpened;
|
|
|
|
|
setViewExtensionOpened: (showViewExtension?: ViewExtensionOpened) => void;
|
2025-01-21 19:37:15 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const useSearchStore = create<ISearchStore>()(
|
|
|
|
|
persist(
|
|
|
|
|
(set) => ({
|
|
|
|
|
sourceData: undefined,
|
|
|
|
|
setSourceData: (sourceData: any) => set({ sourceData }),
|
2025-02-26 16:47:46 +08:00
|
|
|
sourceDataIds: [],
|
2025-05-23 18:14:41 +08:00
|
|
|
setSourceDataIds: (sourceDataIds: string[]) => set({ sourceDataIds }),
|
2025-04-24 19:00:16 +08:00
|
|
|
MCPIds: [],
|
|
|
|
|
setMCPIds: (MCPIds: string[]) => set({ MCPIds }),
|
2025-02-27 12:07:58 +08:00
|
|
|
visibleContextMenu: false,
|
2025-02-27 16:02:09 +08:00
|
|
|
setVisibleContextMenu: (visibleContextMenu) => {
|
|
|
|
|
return set({ visibleContextMenu });
|
|
|
|
|
},
|
|
|
|
|
setSelectedSearchContent: (selectedSearchContent) => {
|
|
|
|
|
return set({ selectedSearchContent });
|
|
|
|
|
},
|
2025-05-23 18:14:41 +08:00
|
|
|
goAskAi: false,
|
|
|
|
|
setGoAskAi: (goAskAi) => {
|
|
|
|
|
return set({ goAskAi });
|
|
|
|
|
},
|
|
|
|
|
askAiMessage: "",
|
|
|
|
|
setAskAiMessage: (askAiMessage) => {
|
|
|
|
|
return set({ askAiMessage });
|
|
|
|
|
},
|
|
|
|
|
setAskAiSessionId: (askAiSessionId) => {
|
|
|
|
|
return set({ askAiSessionId });
|
|
|
|
|
},
|
|
|
|
|
setSelectedAssistant: (selectedAssistant) => {
|
|
|
|
|
return set({ selectedAssistant });
|
|
|
|
|
},
|
2025-05-26 10:56:29 +08:00
|
|
|
setAskAiServerId: (askAiServerId) => {
|
|
|
|
|
return set({ askAiServerId });
|
|
|
|
|
},
|
2025-05-30 17:18:52 +08:00
|
|
|
enabledAiOverview: false,
|
|
|
|
|
setEnabledAiOverview: (enabledAiOverview) => {
|
|
|
|
|
return set({ enabledAiOverview });
|
|
|
|
|
},
|
|
|
|
|
setAskAiAssistantId: (askAiAssistantId) => {
|
|
|
|
|
return set({ askAiAssistantId });
|
|
|
|
|
},
|
2025-12-05 15:32:57 +08:00
|
|
|
setTargetServerId: (targetServerId) => {
|
|
|
|
|
return set({ targetServerId });
|
|
|
|
|
},
|
2025-11-27 10:12:49 +08:00
|
|
|
setTargetAssistantId: (targetAssistantId) => {
|
|
|
|
|
return set({ targetAssistantId });
|
|
|
|
|
},
|
2025-06-26 18:40:33 +08:00
|
|
|
visibleExtensionStore: false,
|
|
|
|
|
setVisibleExtensionStore: (visibleExtensionStore) => {
|
|
|
|
|
return set({ visibleExtensionStore });
|
|
|
|
|
},
|
|
|
|
|
searchValue: "",
|
|
|
|
|
setSearchValue: (searchValue) => {
|
|
|
|
|
return set({ searchValue });
|
|
|
|
|
},
|
|
|
|
|
setSelectedExtension(selectedExtension) {
|
|
|
|
|
return set({ selectedExtension });
|
|
|
|
|
},
|
|
|
|
|
installingExtensions: [],
|
|
|
|
|
setInstallingExtensions: (installingExtensions) => {
|
|
|
|
|
return set({ installingExtensions });
|
|
|
|
|
},
|
|
|
|
|
uninstallingExtensions: [],
|
|
|
|
|
setUninstallingExtensions: (uninstallingExtensions) => {
|
|
|
|
|
return set({ uninstallingExtensions });
|
|
|
|
|
},
|
|
|
|
|
visibleExtensionDetail: false,
|
|
|
|
|
setVisibleExtensionDetail: (visibleExtensionDetail) => {
|
|
|
|
|
return set({ visibleExtensionDetail });
|
|
|
|
|
},
|
feat: new extension type View (#894)
This commit introduces a new extension type View, which enables developers
to implement extensions with GUI. It is implemented using iframe, developers
can specify the path to the HTML file in the `Extension.page` field, then
Coco will load and render that page when the extension gets opened.
coco-api
We provide a TypeScript library [1] that will contain the APIs developers
need to make the experience better.
We start from file system APIs. Since the embedded HTML page will be loaded
by WebView, which has no access to the local file system, we provide APIs
to bridge that gap. Currently, `fs:read_dir()` is the only API we implemented, more
will come soon.
Permission
As View extensions run user-provided code, we introduce a permision
mechanism to sandbox the code. Developers must manually specify the
permission their extension needs in the "plugin.json" file, e,g.:
"permissions": {
"fs": [
{ "path": "/Users/foo/Downloads", "access": ["read", "write"] },
{ "path": "/Users/foo/Documents", "access": ["read"] }
],
"http": [
{ "host": "api.github.com" }
],
"api": ["fs:read_dir"]
}
Currently, both fs and api permissions are implemented. Permission checks
apply only to View extensions for now; Command extensions will support
them in the future.
[1]: https://github.com/infinilabs/coco-api
2025-09-25 11:12:29 +08:00
|
|
|
setViewExtensionOpened: (viewExtensionOpened) => {
|
|
|
|
|
return set({ viewExtensionOpened });
|
|
|
|
|
},
|
2025-01-21 19:37:15 +08:00
|
|
|
}),
|
|
|
|
|
{
|
|
|
|
|
name: "search-store",
|
|
|
|
|
partialize: (state) => ({
|
|
|
|
|
sourceData: state.sourceData,
|
|
|
|
|
}),
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
);
|