mirror of
https://github.com/project-gauntlet/gauntlet.git
synced 2025-12-23 10:35:53 +00:00
Add command entrypoints
This commit is contained in:
parent
0745e52cd4
commit
7b6d8b8a09
25 changed files with 296 additions and 107 deletions
|
|
@ -7,13 +7,14 @@ import { parse as parseToml } from "toml";
|
|||
import { z } from "zod";
|
||||
|
||||
const Config = z.strictObject({
|
||||
metadata: z.strictObject({
|
||||
gauntlet: z.strictObject({
|
||||
name: z.string()
|
||||
}),
|
||||
entrypoint: z.array(z.strictObject({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
path: z.string()
|
||||
path: z.string(),
|
||||
type: z.enum(["command", "view"])
|
||||
})),
|
||||
permissions: z.strictObject({
|
||||
environment: z.array(z.string()).default([]),
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
"@rollup/plugin-typescript": "^11.1.5",
|
||||
"@types/react": "^18.2.35",
|
||||
"@project-gauntlet/typings": "*",
|
||||
"@project-gauntlet/deno": "*",
|
||||
"rollup": "^4.3.0",
|
||||
"tslib": "^2.6.2",
|
||||
"typescript": "^5.2.2"
|
||||
|
|
|
|||
|
|
@ -82,17 +82,22 @@ async function runLoop() {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case "ViewCreated": {
|
||||
case "OpenView": {
|
||||
try {
|
||||
const view: FC = (await import(`gauntlet:view?${pluginEvent.viewName}`)).default;
|
||||
const view: FC = (await import(`gauntlet:entrypoint?${pluginEvent.entrypointId}`)).default;
|
||||
const {render} = await import("gauntlet:renderer");
|
||||
latestRootUiWidget = render(pluginEvent.reconcilerMode, view);
|
||||
latestRootUiWidget = render(pluginEvent.frontend, view);
|
||||
} catch (e) {
|
||||
console.error("Error occurred when rendering view", pluginEvent.viewName, e)
|
||||
console.error("Error occurred when rendering view", pluginEvent.entrypointId, e)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "ViewDestroyed": {
|
||||
case "RunCommand": {
|
||||
try {
|
||||
await import(`gauntlet:entrypoint?${pluginEvent.entrypointId}`)
|
||||
} catch (e) {
|
||||
console.error("Error occurred when running a command", pluginEvent.entrypointId, e)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "PluginCommand": {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
"target": "ES2022",
|
||||
"moduleResolution": "bundler",
|
||||
"jsx": "react-jsx",
|
||||
"types": ["@project-gauntlet/typings"]
|
||||
"types": ["@project-gauntlet/typings", "@project-gauntlet/deno"]
|
||||
},
|
||||
"lib": ["ES2020"]
|
||||
}
|
||||
2
js/core/typings/index.d.ts
vendored
2
js/core/typings/index.d.ts
vendored
|
|
@ -1,6 +1,6 @@
|
|||
declare module "gauntlet:renderer" {
|
||||
import { FC } from "react";
|
||||
|
||||
const render: (mode: "mutation" | "persistent", component: FC) => RootUiWidget;
|
||||
const render: (frontend: string, component: FC) => RootUiWidget;
|
||||
export { render };
|
||||
}
|
||||
|
|
@ -1,18 +1,27 @@
|
|||
[metadata]
|
||||
name='Interesting Plugin Name'
|
||||
[gauntlet]
|
||||
name = 'Interesting Plugin Name'
|
||||
|
||||
[[entrypoint]]
|
||||
id='detail-view'
|
||||
name='Detail view'
|
||||
path='src/detail-view.tsx'
|
||||
id = 'detail-view'
|
||||
name = 'Detail view'
|
||||
path = 'src/detail-view.tsx'
|
||||
type = 'view'
|
||||
|
||||
[[entrypoint]]
|
||||
id='form-view'
|
||||
name='Form view'
|
||||
path='src/form-view.tsx'
|
||||
id = 'form-view'
|
||||
name = 'Form view'
|
||||
path = 'src/form-view.tsx'
|
||||
type = 'view'
|
||||
|
||||
[[entrypoint]]
|
||||
id = 'command-a'
|
||||
name = 'Command A'
|
||||
path = 'src/command-a.ts'
|
||||
type = 'command'
|
||||
|
||||
[[supported_system]]
|
||||
os='linux'
|
||||
os = 'linux'
|
||||
|
||||
[permissions]
|
||||
environment=["RUST_LOG"]
|
||||
environment = ["RUST_LOG"]
|
||||
system=["systemMemoryInfo"]
|
||||
|
|
@ -6,11 +6,11 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.14",
|
||||
"@project-gauntlet/deno": "*",
|
||||
"@project-gauntlet/binary": "*"
|
||||
},
|
||||
"dependencies": {
|
||||
"@project-gauntlet/api": "*",
|
||||
"@project-gauntlet/deno": "*",
|
||||
"@types/lodash": "^4.14.196",
|
||||
"lodash": "^4.17.21"
|
||||
}
|
||||
|
|
|
|||
3
js/dev_plugin/src/command-a.ts
Normal file
3
js/dev_plugin/src/command-a.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
const systemMemoryInfo = Deno.systemMemoryInfo();
|
||||
|
||||
console.dir(systemMemoryInfo)
|
||||
|
|
@ -15,6 +15,7 @@
|
|||
"@types/react": "^18.2.35",
|
||||
"@types/react-reconciler": "^0.28.6",
|
||||
"@project-gauntlet/typings": "*",
|
||||
"@project-gauntlet/deno": "*",
|
||||
"rollup": "^4.3.0",
|
||||
"tslib": "^2.6.2",
|
||||
"typescript": "^5.2.2"
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ function createWidget(hostContext: HostContext, type: ComponentType, properties:
|
|||
return instance
|
||||
}
|
||||
|
||||
export const createHostConfig = (options: { mode: "mutation" | "persistent" }): HostConfig<
|
||||
export const createHostConfig = (): HostConfig<
|
||||
ComponentType,
|
||||
PropsWithChildren,
|
||||
RootUiWidget,
|
||||
|
|
@ -159,7 +159,7 @@ export const createHostConfig = (options: { mode: "mutation" | "persistent" }):
|
|||
/*
|
||||
persistence items
|
||||
*/
|
||||
supportsPersistence: isPersistentMode(options.mode),
|
||||
supportsPersistence: true,
|
||||
|
||||
cloneInstance(
|
||||
instance: Instance,
|
||||
|
|
@ -171,8 +171,6 @@ export const createHostConfig = (options: { mode: "mutation" | "persistent" }):
|
|||
keepChildren: boolean,
|
||||
recyclableInstance: null | Instance,
|
||||
): Instance {
|
||||
assertPersistentMode(options.mode);
|
||||
|
||||
InternalApi.op_log_trace("renderer_js_persistence", `cloneInstance is called, instance: ${Deno.inspect(instance)}, updatePayload: ${Deno.inspect(updatePayload)}, type: ${type}, oldProps: ${Deno.inspect(oldProps)}, newProps: ${Deno.inspect(newProps)}, keepChildren: ${keepChildren}, recyclableInstance: ${Deno.inspect(recyclableInstance)}`)
|
||||
|
||||
// TODO validate
|
||||
|
|
@ -200,26 +198,22 @@ export const createHostConfig = (options: { mode: "mutation" | "persistent" }):
|
|||
},
|
||||
|
||||
createContainerChildSet(container: RootUiWidget): ChildSet {
|
||||
assertPersistentMode(options.mode);
|
||||
InternalApi.op_log_trace("renderer_js_persistence", `createContainerChildSet is called, container: ${Deno.inspect(container)}`)
|
||||
|
||||
return []
|
||||
},
|
||||
|
||||
appendChildToContainerChildSet(childSet: ChildSet, child: Instance | TextInstance): void {
|
||||
assertPersistentMode(options.mode);
|
||||
InternalApi.op_log_trace("renderer_js_persistence", `appendChildToContainerChildSet is called, childSet: ${Deno.inspect(childSet)}, child: ${Deno.inspect(child)}`)
|
||||
|
||||
childSet.push(child);
|
||||
},
|
||||
|
||||
finalizeContainerChildren(container: RootUiWidget, newChildren: ChildSet): void {
|
||||
assertPersistentMode(options.mode);
|
||||
InternalApi.op_log_trace("renderer_js_persistence", `finalizeContainerChildren is called, container: ${Deno.inspect(container)}, newChildren: ${Deno.inspect(newChildren)}`)
|
||||
},
|
||||
|
||||
replaceContainerChildren(container: RootUiWidget, newChildren: ChildSet): void {
|
||||
assertPersistentMode(options.mode);
|
||||
InternalApi.op_log_trace("renderer_js_persistence", `replaceContainerChildren is called, container: ${Deno.inspect(container)}, newChildren: ${Deno.inspect(newChildren)}`)
|
||||
container.widgetChildren = newChildren
|
||||
InternalApi.op_react_replace_container_children(container, newChildren)
|
||||
|
|
@ -244,13 +238,6 @@ export const createHostConfig = (options: { mode: "mutation" | "persistent" }):
|
|||
supportsHydration: false
|
||||
});
|
||||
|
||||
const isPersistentMode = (mode: "mutation" | "persistent") => mode === "persistent";
|
||||
const assertPersistentMode = (mode: "mutation" | "persistent") => {
|
||||
if (!isPersistentMode(mode)) {
|
||||
throw new Error("Wrong reconciler mode")
|
||||
}
|
||||
}
|
||||
|
||||
function shallowDiff(oldObj: Record<string, any>, newObj: Record<string, any>): string[] | null {
|
||||
const uniqueProps = new Set([...Object.keys(oldObj), ...Object.keys(newObj)]);
|
||||
const diff = Array.from(uniqueProps)
|
||||
|
|
@ -289,13 +276,13 @@ const createTracedHostConfig = (hostConfig: any) => new Proxy(hostConfig, {
|
|||
}
|
||||
});
|
||||
|
||||
export function render(mode: "mutation" | "persistent", View: React.FC): RootUiWidget {
|
||||
if (mode === "mutation") {
|
||||
// TODO reimplement but for specific frontend, it seems it is not feasible to do generic implementation
|
||||
throw new Error("NOT IMPLEMENTED")
|
||||
export function render(frontend: string, View: React.FC): RootUiWidget {
|
||||
// specific frontend are implemented separately, it seems it is not feasible to do generic implementation
|
||||
if (frontend !== "default") {
|
||||
throw new Error("NOT SUPPORTED")
|
||||
}
|
||||
|
||||
const hostConfig = createHostConfig({mode});
|
||||
const hostConfig = createHostConfig();
|
||||
|
||||
// const reconciler = ReactReconciler(createTracedHostConfig(hostConfig));
|
||||
const reconciler = ReactReconciler(hostConfig);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
"target": "ES2022",
|
||||
"moduleResolution": "bundler",
|
||||
"jsx": "react-jsx",
|
||||
"types": ["@project-gauntlet/typings"]
|
||||
"types": ["@project-gauntlet/typings", "@project-gauntlet/deno"]
|
||||
},
|
||||
"lib": ["ES2020"]
|
||||
}
|
||||
16
js/typings/index.d.ts
vendored
16
js/typings/index.d.ts
vendored
|
|
@ -11,7 +11,7 @@ interface Deno {
|
|||
};
|
||||
}
|
||||
|
||||
type PluginEvent = ViewEvent | ViewCreated | ViewDestroyed | PluginCommand
|
||||
type PluginEvent = ViewEvent | RunCommand | OpenView | PluginCommand
|
||||
|
||||
type ViewEvent = {
|
||||
type: "ViewEvent"
|
||||
|
|
@ -20,14 +20,14 @@ type ViewEvent = {
|
|||
eventArguments: PropertyValue[]
|
||||
}
|
||||
|
||||
type ViewCreated = {
|
||||
type: "ViewCreated"
|
||||
reconcilerMode: string
|
||||
viewName: string
|
||||
type OpenView = {
|
||||
type: "OpenView"
|
||||
frontend: string
|
||||
entrypointId: string
|
||||
}
|
||||
|
||||
type ViewDestroyed = {
|
||||
type: "ViewDestroyed"
|
||||
type RunCommand = {
|
||||
type: "RunCommand"
|
||||
entrypointId: string
|
||||
}
|
||||
|
||||
type PluginCommand = {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use zbus::DBusError;
|
||||
|
||||
use common::dbus::{DbusEventViewCreated, DbusEventViewEvent, DBusSearchResult, DBusUiWidget};
|
||||
use common::dbus::{DbusEventOpenView, DbusEventRunCommand, DbusEventViewEvent, DBusSearchResult, DBusUiWidget};
|
||||
use common::model::PluginId;
|
||||
use utils::channel::RequestSender;
|
||||
|
||||
|
|
@ -13,7 +13,10 @@ pub struct DbusClient {
|
|||
#[zbus::dbus_interface(name = "dev.projectgauntlet.Client")]
|
||||
impl DbusClient {
|
||||
#[dbus_interface(signal)]
|
||||
pub async fn view_created_signal(signal_ctxt: &zbus::SignalContext<'_>, plugin_id: &str, event: DbusEventViewCreated) -> zbus::Result<()>;
|
||||
pub async fn open_view_signal(signal_ctxt: &zbus::SignalContext<'_>, plugin_id: &str, event: DbusEventOpenView) -> zbus::Result<()>;
|
||||
|
||||
#[dbus_interface(signal)]
|
||||
pub async fn run_command_signal(signal_ctxt: &zbus::SignalContext<'_>, plugin_id: &str, event: DbusEventRunCommand) -> zbus::Result<()>;
|
||||
|
||||
#[dbus_interface(signal)]
|
||||
pub async fn view_event_signal(signal_ctxt: &zbus::SignalContext<'_>, plugin_id: &str, event: DbusEventViewEvent) -> zbus::Result<()>;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,13 @@ pub struct NativeUiSearchResult {
|
|||
pub plugin_name: String,
|
||||
pub entrypoint_id: EntrypointId,
|
||||
pub entrypoint_name: String,
|
||||
pub entrypoint_type: SearchResultEntrypointType,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum SearchResultEntrypointType {
|
||||
Command,
|
||||
View,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
|||
|
|
@ -11,12 +11,12 @@ use iced_aw::graphics::icons;
|
|||
use tokio::sync::RwLock as TokioRwLock;
|
||||
use zbus::{Connection, InterfaceRef};
|
||||
|
||||
use common::dbus::DbusEventViewCreated;
|
||||
use common::dbus::{DBusEntrypointType, DbusEventOpenView, DbusEventRunCommand};
|
||||
use common::model::{EntrypointId, PluginId};
|
||||
use utils::channel::{channel, RequestReceiver};
|
||||
|
||||
use crate::dbus::{DbusClient, DbusServerProxyProxy};
|
||||
use crate::model::{NativeUiRequestData, NativeUiResponseData, NativeUiSearchResult};
|
||||
use crate::model::{NativeUiRequestData, NativeUiResponseData, NativeUiSearchResult, SearchResultEntrypointType};
|
||||
use crate::ui::plugin_container::{ClientContext, plugin_container};
|
||||
use crate::ui::search_list::search_list;
|
||||
use crate::ui::theme::{ContainerStyle, Element, GauntletTheme};
|
||||
|
|
@ -53,6 +53,10 @@ pub enum AppMsg {
|
|||
plugin_id: PluginId,
|
||||
entrypoint_id: EntrypointId,
|
||||
},
|
||||
RunCommand {
|
||||
plugin_id: PluginId,
|
||||
entrypoint_id: EntrypointId,
|
||||
},
|
||||
PromptChanged(String),
|
||||
SetSearchResults(Vec<NativeUiSearchResult>),
|
||||
IcedEvent(Event),
|
||||
|
|
@ -151,14 +155,14 @@ impl Application for AppModel {
|
|||
let dbus_client = self.dbus_client.clone();
|
||||
|
||||
let open_view = Command::perform(async move {
|
||||
let event_view_created = DbusEventViewCreated {
|
||||
reconciler_mode: "persistent".to_owned(),
|
||||
view_name: entrypoint_id.to_string(), // TODO what was view_name supposed to be?
|
||||
let event_open_view = DbusEventOpenView {
|
||||
frontend: "default".to_owned(),
|
||||
entrypoint_id: entrypoint_id.to_string(),
|
||||
};
|
||||
|
||||
let signal_context = dbus_client.signal_context();
|
||||
|
||||
DbusClient::view_created_signal(signal_context, &plugin_id.to_string(), event_view_created)
|
||||
DbusClient::open_view_signal(signal_context, &plugin_id.to_string(), event_open_view)
|
||||
.await
|
||||
.unwrap();
|
||||
}, |_| AppMsg::Noop);
|
||||
|
|
@ -168,6 +172,26 @@ impl Application for AppModel {
|
|||
open_view
|
||||
])
|
||||
}
|
||||
AppMsg::RunCommand { plugin_id, entrypoint_id } => {
|
||||
let dbus_client = self.dbus_client.clone();
|
||||
|
||||
let run_command = Command::perform(async move {
|
||||
let event_run_command = DbusEventRunCommand {
|
||||
entrypoint_id: entrypoint_id.to_string(),
|
||||
};
|
||||
|
||||
let signal_context = dbus_client.signal_context();
|
||||
|
||||
DbusClient::run_command_signal(signal_context, &plugin_id.to_string(), event_run_command)
|
||||
.await
|
||||
.unwrap();
|
||||
}, |_| AppMsg::Noop);
|
||||
|
||||
Command::batch([
|
||||
run_command,
|
||||
iced::window::close(),
|
||||
])
|
||||
}
|
||||
AppMsg::PromptChanged(new_prompt) => {
|
||||
match self.state.last_mut().expect("state is supposed to always have at least one item") {
|
||||
NavState::SearchView { prompt } => {
|
||||
|
|
@ -185,6 +209,10 @@ impl Application for AppModel {
|
|||
plugin_name: search_result.plugin_name,
|
||||
entrypoint_id: EntrypointId::new(search_result.entrypoint_id),
|
||||
entrypoint_name: search_result.entrypoint_name,
|
||||
entrypoint_type: match search_result.entrypoint_type {
|
||||
DBusEntrypointType::Command => SearchResultEntrypointType::Command,
|
||||
DBusEntrypointType::View => SearchResultEntrypointType::View,
|
||||
},
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
|
@ -258,12 +286,17 @@ impl Application for AppModel {
|
|||
|
||||
let search_results = self.search_results.iter().cloned().collect();
|
||||
|
||||
let search_list = search_list(search_results, |event| {
|
||||
AppMsg::OpenView {
|
||||
let search_list = search_list(
|
||||
search_results,
|
||||
|event| AppMsg::OpenView {
|
||||
plugin_id: event.plugin_id,
|
||||
entrypoint_id: event.entrypoint_id,
|
||||
}
|
||||
});
|
||||
},
|
||||
|event| AppMsg::RunCommand {
|
||||
plugin_id: event.plugin_id,
|
||||
entrypoint_id: event.entrypoint_id,
|
||||
},
|
||||
);
|
||||
|
||||
let list: Element<_> = scrollable(search_list)
|
||||
.width(Length::Fill)
|
||||
|
|
|
|||
|
|
@ -8,19 +8,21 @@ use iced::widget::text;
|
|||
|
||||
use common::model::{EntrypointId, PluginId};
|
||||
|
||||
use crate::model::NativeUiSearchResult;
|
||||
use crate::model::{NativeUiSearchResult, SearchResultEntrypointType};
|
||||
use crate::ui::theme::{ButtonStyle, Element, GauntletRenderer, TextStyle};
|
||||
|
||||
pub struct SearchList<Message> {
|
||||
on_open_view: Box<dyn Fn(OpenViewEvent) -> Message>,
|
||||
on_run_command: Box<dyn Fn(RunCommandEvent) -> Message>,
|
||||
search_results: Vec<NativeUiSearchResult>,
|
||||
}
|
||||
|
||||
pub fn search_list<Message>(
|
||||
search_results: Vec<NativeUiSearchResult>,
|
||||
on_open_view: impl Fn(OpenViewEvent) -> Message + 'static
|
||||
on_open_view: impl Fn(OpenViewEvent) -> Message + 'static,
|
||||
on_run_command: impl Fn(RunCommandEvent) -> Message + 'static
|
||||
) -> SearchList<Message> {
|
||||
SearchList::new(search_results, on_open_view)
|
||||
SearchList::new(search_results, on_open_view, on_run_command)
|
||||
}
|
||||
|
||||
pub struct OpenViewEvent {
|
||||
|
|
@ -28,8 +30,17 @@ pub struct OpenViewEvent {
|
|||
pub entrypoint_id: EntrypointId,
|
||||
}
|
||||
|
||||
pub struct RunCommandEvent {
|
||||
pub plugin_id: PluginId,
|
||||
pub entrypoint_id: EntrypointId,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Event {
|
||||
RunCommand {
|
||||
plugin_id: PluginId,
|
||||
entrypoint_id: EntrypointId,
|
||||
},
|
||||
OpenView {
|
||||
plugin_id: PluginId,
|
||||
entrypoint_id: EntrypointId,
|
||||
|
|
@ -37,10 +48,15 @@ pub enum Event {
|
|||
}
|
||||
|
||||
impl<Message> SearchList<Message> {
|
||||
pub fn new(search_results: Vec<NativeUiSearchResult>, on_open_view: impl Fn(OpenViewEvent) -> Message + 'static) -> Self {
|
||||
pub fn new(
|
||||
search_results: Vec<NativeUiSearchResult>,
|
||||
on_open_view: impl Fn(OpenViewEvent) -> Message + 'static,
|
||||
on_run_command: impl Fn(RunCommandEvent) -> Message + 'static
|
||||
) -> Self {
|
||||
Self {
|
||||
search_results,
|
||||
on_open_view: Box::new(on_open_view),
|
||||
on_run_command: Box::new(on_run_command),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -59,6 +75,10 @@ impl<Message> Component<Message, GauntletRenderer> for SearchList<Message> {
|
|||
let event = OpenViewEvent { plugin_id, entrypoint_id, };
|
||||
Some((self.on_open_view)(event))
|
||||
}
|
||||
Event::RunCommand { plugin_id, entrypoint_id } => {
|
||||
let event = RunCommandEvent { plugin_id, entrypoint_id, };
|
||||
Some((self.on_run_command)(event))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -84,10 +104,21 @@ impl<Message> Component<Message, GauntletRenderer> for SearchList<Message> {
|
|||
sub_text,
|
||||
]).into();
|
||||
|
||||
let event = match search_result.entrypoint_type {
|
||||
SearchResultEntrypointType::Command => Event::RunCommand {
|
||||
entrypoint_id: search_result.entrypoint_id.clone(),
|
||||
plugin_id: search_result.plugin_id.clone()
|
||||
},
|
||||
SearchResultEntrypointType::View => Event::OpenView {
|
||||
entrypoint_id: search_result.entrypoint_id.clone(),
|
||||
plugin_id: search_result.plugin_id.clone()
|
||||
}
|
||||
};
|
||||
|
||||
button(button_content)
|
||||
.width(Length::Fill)
|
||||
.style(ButtonStyle::EntrypointItem)
|
||||
.on_press(Event::OpenView { entrypoint_id: search_result.entrypoint_id.clone(), plugin_id: search_result.plugin_id.clone() })
|
||||
.on_press(event)
|
||||
.padding(Padding::new(5.0))
|
||||
.into()
|
||||
})
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ pub struct DBusSearchResult {
|
|||
pub plugin_name: String,
|
||||
pub entrypoint_id: String,
|
||||
pub entrypoint_name: String,
|
||||
pub entrypoint_type: DBusEntrypointType,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Type)]
|
||||
|
|
@ -25,6 +26,7 @@ pub struct DBusEntrypoint {
|
|||
pub entrypoint_id: String,
|
||||
pub entrypoint_name: String,
|
||||
pub enabled: bool,
|
||||
pub entrypoint_type: DBusEntrypointType,
|
||||
}
|
||||
|
||||
#[derive(Debug, DeserializeDict, SerializeDict, Type)]
|
||||
|
|
@ -36,11 +38,15 @@ pub struct DBusUiWidget {
|
|||
pub widget_children: Vec<DBusUiWidget>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Type)]
|
||||
pub struct DbusEventOpenView {
|
||||
pub frontend: String,
|
||||
pub entrypoint_id: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Type)]
|
||||
pub struct DbusEventViewCreated {
|
||||
pub reconciler_mode: String,
|
||||
pub view_name: String,
|
||||
pub struct DbusEventRunCommand {
|
||||
pub entrypoint_id: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Type)]
|
||||
|
|
@ -50,6 +56,12 @@ pub struct DbusEventViewEvent {
|
|||
pub event_arguments: Vec<DBusUiPropertyValue>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Type)]
|
||||
pub enum DBusEntrypointType {
|
||||
Command,
|
||||
View,
|
||||
}
|
||||
|
||||
pub type DbusUiWidgetId = u32;
|
||||
pub type DbusUiEventName = String;
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ CREATE TABLE plugin_entrypoint
|
|||
plugin_id TEXT NOT NULL REFERENCES plugin (id) ON DELETE CASCADE,
|
||||
name TEXT NOT NULL,
|
||||
enabled BOOLEAN NOT NULL,
|
||||
type TEXT NOT NULL,
|
||||
PRIMARY KEY (id, plugin_id)
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
use std::fmt::Debug;
|
||||
|
||||
use zbus::DBusError;
|
||||
|
||||
use common::dbus::{DbusEventViewCreated, DbusEventViewEvent, DBusPlugin, DBusSearchResult, DBusUiWidget};
|
||||
use common::dbus::{DBusEntrypointType, DbusEventOpenView, DbusEventRunCommand, DbusEventViewEvent, DBusPlugin, DBusSearchResult, DBusUiWidget};
|
||||
use common::model::{EntrypointId, PluginId};
|
||||
|
||||
use crate::model::PluginEntrypointType;
|
||||
use crate::plugins::ApplicationManager;
|
||||
use crate::search::SearchIndex;
|
||||
|
||||
|
|
@ -18,6 +21,10 @@ impl DbusServer {
|
|||
.into_iter()
|
||||
.map(|item| {
|
||||
DBusSearchResult {
|
||||
entrypoint_type: match item.entrypoint_type {
|
||||
PluginEntrypointType::Command => DBusEntrypointType::Command,
|
||||
PluginEntrypointType::View => DBusEntrypointType::View,
|
||||
},
|
||||
entrypoint_name: item.entrypoint_name,
|
||||
entrypoint_id: item.entrypoint_id,
|
||||
plugin_name: item.plugin_name,
|
||||
|
|
@ -37,7 +44,6 @@ pub struct DbusManagementServer {
|
|||
|
||||
#[zbus::dbus_interface(name = "dev.projectgauntlet.Server.Management")]
|
||||
impl DbusManagementServer {
|
||||
|
||||
#[dbus_interface(signal)]
|
||||
pub async fn remote_plugin_download_finished_signal(signal_ctxt: &zbus::SignalContext<'_>, plugin_id: &str) -> zbus::Result<()>;
|
||||
|
||||
|
|
@ -45,7 +51,7 @@ impl DbusManagementServer {
|
|||
&mut self,
|
||||
#[zbus(signal_context)]
|
||||
signal_context: zbus::SignalContext<'_>,
|
||||
plugin_id: &str
|
||||
plugin_id: &str,
|
||||
) -> Result<()> {
|
||||
self.application_manager.download_and_add_plugin(signal_context, PluginId::from_string(plugin_id))
|
||||
.await
|
||||
|
|
@ -89,13 +95,16 @@ impl From<anyhow::Error> for ServerError {
|
|||
|
||||
|
||||
#[zbus::dbus_proxy(
|
||||
default_service = "dev.projectgauntlet.Gauntlet.Client",
|
||||
default_path = "/dev/projectgauntlet/Client",
|
||||
interface = "dev.projectgauntlet.Client",
|
||||
default_service = "dev.projectgauntlet.Gauntlet.Client",
|
||||
default_path = "/dev/projectgauntlet/Client",
|
||||
interface = "dev.projectgauntlet.Client",
|
||||
)]
|
||||
trait DbusClientProxy {
|
||||
#[dbus_proxy(signal)]
|
||||
fn view_created_signal(&self, plugin_id: &str, event: DbusEventViewCreated) -> zbus::Result<()>;
|
||||
fn open_view_signal(&self, plugin_id: &str, event: DbusEventOpenView) -> zbus::Result<()>;
|
||||
|
||||
#[dbus_proxy(signal)]
|
||||
fn run_command_signal(&self, plugin_id: &str, event: DbusEventRunCommand) -> zbus::Result<()>;
|
||||
|
||||
#[dbus_proxy(signal)]
|
||||
fn view_event_signal(&self, plugin_id: &str, event: DbusEventViewEvent) -> zbus::Result<()>;
|
||||
|
|
|
|||
|
|
@ -24,13 +24,16 @@ pub type UiWidgetId = u32;
|
|||
#[derive(Deserialize, Serialize)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum JsUiEvent {
|
||||
ViewCreated {
|
||||
#[serde(rename = "reconcilerMode")]
|
||||
reconciler_mode: String,
|
||||
#[serde(rename = "viewName")]
|
||||
view_name: String
|
||||
OpenView {
|
||||
#[serde(rename = "frontend")]
|
||||
frontend: String,
|
||||
#[serde(rename = "entrypointId")]
|
||||
entrypoint_id: String
|
||||
},
|
||||
RunCommand {
|
||||
#[serde(rename = "entrypointId")]
|
||||
entrypoint_id: String
|
||||
},
|
||||
ViewDestroyed,
|
||||
ViewEvent {
|
||||
#[serde(rename = "widgetId")]
|
||||
widget_id: UiWidgetId,
|
||||
|
|
@ -75,9 +78,12 @@ pub struct JsUiWidget<'a> {
|
|||
|
||||
#[derive(Debug)]
|
||||
pub enum IntermediateUiEvent {
|
||||
ViewCreated {
|
||||
reconciler_mode: String,
|
||||
view_name: String
|
||||
OpenView {
|
||||
frontend: String,
|
||||
entrypoint_id: String
|
||||
},
|
||||
RunCommand {
|
||||
entrypoint_id: String
|
||||
},
|
||||
ViewEvent {
|
||||
widget_id: UiWidgetId,
|
||||
|
|
@ -160,3 +166,26 @@ fn from_intermediate_to_dbus_properties(value: HashMap<String, IntermediatePrope
|
|||
|
||||
DBusUiPropertyContainer(properties)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum PluginEntrypointType {
|
||||
Command,
|
||||
View,
|
||||
}
|
||||
|
||||
pub fn entrypoint_to_str(value: PluginEntrypointType) -> &'static str {
|
||||
match value {
|
||||
PluginEntrypointType::Command => "command",
|
||||
PluginEntrypointType::View => "view",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn entrypoint_from_str(value: &str) -> PluginEntrypointType {
|
||||
match value {
|
||||
"command" => PluginEntrypointType::Command,
|
||||
"view" => PluginEntrypointType::View,
|
||||
_ => {
|
||||
panic!("index contains illegal entrypoint_type: {}", value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -51,6 +51,8 @@ pub struct GetPluginEntrypoint {
|
|||
pub plugin_id: String,
|
||||
pub name: String,
|
||||
pub enabled: bool,
|
||||
#[sqlx(rename = "type")]
|
||||
pub entrypoint_type: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
|
|
@ -70,6 +72,7 @@ pub struct SavePlugin {
|
|||
pub struct SavePluginEntrypoint {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub entrypoint_type: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
|
|
@ -254,11 +257,12 @@ impl DataDbRepository {
|
|||
|
||||
for entrypoint in plugin.entrypoints {
|
||||
// language=SQLite
|
||||
sqlx::query("INSERT INTO plugin_entrypoint VALUES(?1, ?2, ?3, ?4)")
|
||||
sqlx::query("INSERT INTO plugin_entrypoint VALUES(?1, ?2, ?3, ?4, ?5)")
|
||||
.bind(entrypoint.id)
|
||||
.bind(&plugin.id)
|
||||
.bind(entrypoint.name)
|
||||
.bind(true)
|
||||
.bind(entrypoint.entrypoint_type)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use regex::Regex;
|
|||
use common::model::PluginId;
|
||||
use component_model::{Children, Component, create_component_model, PropertyType};
|
||||
|
||||
use crate::dbus::{DbusClientProxyProxy, ViewCreatedSignal, ViewEventSignal};
|
||||
use crate::dbus::{DbusClientProxyProxy, OpenViewSignal, RunCommandSignal, ViewEventSignal};
|
||||
use crate::model::{from_dbus_to_intermediate_value, IntermediatePropertyValue, IntermediateUiEvent, IntermediateUiWidget, JsPropertyValue, JsUiEvent, JsUiRequestData, JsUiResponseData, JsUiWidget};
|
||||
use crate::plugins::run_status::RunStatusGuard;
|
||||
|
||||
|
|
@ -63,9 +63,9 @@ pub async fn start_plugin_runtime(data: PluginRuntimeData, run_status_guard: Run
|
|||
let component_model = create_component_model();
|
||||
|
||||
let plugin_id = data.id.clone();
|
||||
let view_created_signal = client_proxy.receive_view_created_signal()
|
||||
let run_command_signal = client_proxy.receive_run_command_signal()
|
||||
.await?
|
||||
.filter_map(move |signal: ViewCreatedSignal| {
|
||||
.filter_map(move |signal: RunCommandSignal| {
|
||||
let plugin_id = plugin_id.clone();
|
||||
async move {
|
||||
let signal = signal.args().unwrap();
|
||||
|
|
@ -73,9 +73,27 @@ pub async fn start_plugin_runtime(data: PluginRuntimeData, run_status_guard: Run
|
|||
if PluginId::from_string(signal.plugin_id) != plugin_id {
|
||||
None
|
||||
} else {
|
||||
Some(IntermediateUiEvent::ViewCreated {
|
||||
reconciler_mode: signal.event.reconciler_mode,
|
||||
view_name: signal.event.view_name,
|
||||
Some(IntermediateUiEvent::RunCommand {
|
||||
entrypoint_id: signal.event.entrypoint_id,
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let plugin_id = data.id.clone();
|
||||
let open_view_signal = client_proxy.receive_open_view_signal()
|
||||
.await?
|
||||
.filter_map(move |signal: OpenViewSignal| {
|
||||
let plugin_id = plugin_id.clone();
|
||||
async move {
|
||||
let signal = signal.args().unwrap();
|
||||
|
||||
if PluginId::from_string(signal.plugin_id) != plugin_id {
|
||||
None
|
||||
} else {
|
||||
Some(IntermediateUiEvent::OpenView {
|
||||
frontend: signal.event.frontend,
|
||||
entrypoint_id: signal.event.entrypoint_id,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -139,7 +157,7 @@ pub async fn start_plugin_runtime(data: PluginRuntimeData, run_status_guard: Run
|
|||
}
|
||||
});
|
||||
|
||||
let event_stream = (view_event_signal, view_created_signal, command_stream).merge();
|
||||
let event_stream = (run_command_signal, view_event_signal, open_view_signal, command_stream).merge();
|
||||
let event_stream = Box::pin(event_stream);
|
||||
|
||||
let thread_fn = move || {
|
||||
|
|
@ -264,15 +282,15 @@ impl ModuleLoader for CustomModuleLoader {
|
|||
referrer: &str,
|
||||
kind: ResolutionKind,
|
||||
) -> Result<ModuleSpecifier, anyhow::Error> {
|
||||
static PLUGIN_VIEW_PATTERN: Lazy<Regex> = Lazy::new(|| Regex::new(r"^gauntlet:view\?(?<entrypoint_id>[a-zA-Z0-9_-]+)$").expect("invalid regex"));
|
||||
static PLUGIN_ENTRYPOINT_PATTERN: Lazy<Regex> = Lazy::new(|| Regex::new(r"^gauntlet:entrypoint\?(?<entrypoint_id>[a-zA-Z0-9_-]+)$").expect("invalid regex"));
|
||||
static PLUGIN_MODULE_PATTERN: Lazy<Regex> = Lazy::new(|| Regex::new(r"^gauntlet:module\?(?<entrypoint_id>[a-zA-Z0-9_-]+)$").expect("invalid regex"));
|
||||
static PATH_PATTERN: Lazy<Regex> = Lazy::new(|| Regex::new(r"^\./(?<js_module>[a-zA-Z0-9_-]+)\.js$").expect("invalid regex"));
|
||||
|
||||
if PLUGIN_VIEW_PATTERN.is_match(specifier) {
|
||||
if PLUGIN_ENTRYPOINT_PATTERN.is_match(specifier) {
|
||||
return Ok(specifier.parse()?);
|
||||
}
|
||||
|
||||
if PLUGIN_VIEW_PATTERN.is_match(referrer) || PLUGIN_MODULE_PATTERN.is_match(referrer) {
|
||||
if PLUGIN_ENTRYPOINT_PATTERN.is_match(referrer) || PLUGIN_MODULE_PATTERN.is_match(referrer) {
|
||||
if let Some(captures) = PATH_PATTERN.captures(specifier) {
|
||||
return Ok(format!("gauntlet:module?{}", &captures["js_module"]).parse()?);
|
||||
}
|
||||
|
|
@ -301,7 +319,7 @@ impl ModuleLoader for CustomModuleLoader {
|
|||
let mut specifier = module_specifier.clone();
|
||||
specifier.set_query(None);
|
||||
|
||||
if &specifier == &"gauntlet:view".parse().unwrap() || &specifier == &"gauntlet:module".parse().unwrap() {
|
||||
if &specifier == &"gauntlet:entrypoint".parse().unwrap() || &specifier == &"gauntlet:module".parse().unwrap() {
|
||||
let module = get_js_code(module_specifier, &self.code.js);
|
||||
|
||||
return futures::future::ready(module).boxed_local();
|
||||
|
|
@ -312,9 +330,9 @@ impl ModuleLoader for CustomModuleLoader {
|
|||
}
|
||||
|
||||
fn get_js_code(module_specifier: &ModuleSpecifier, js: &HashMap<String, String>) -> anyhow::Result<ModuleSource> {
|
||||
let view_name = module_specifier.query().expect("invalid specifier, should be validated earlier");
|
||||
let entrypoint_id = module_specifier.query().expect("invalid specifier, should be validated earlier");
|
||||
|
||||
let js = js.get(view_name).ok_or(anyhow!("no code provided for view: {:?}", view_name))?;
|
||||
let js = js.get(entrypoint_id).ok_or(anyhow!("no code provided for view: {:?}", entrypoint_id))?;
|
||||
|
||||
let module = ModuleSource::new(ModuleType::JavaScript, js.clone().into(), module_specifier);
|
||||
|
||||
|
|
@ -588,9 +606,12 @@ async fn make_request_async(plugin_id: PluginId, dbus_client: DbusClientProxyPro
|
|||
|
||||
fn from_intermediate_to_js_event(event: IntermediateUiEvent) -> JsUiEvent {
|
||||
match event {
|
||||
IntermediateUiEvent::ViewCreated { reconciler_mode, view_name } => JsUiEvent::ViewCreated {
|
||||
reconciler_mode,
|
||||
view_name,
|
||||
IntermediateUiEvent::OpenView { frontend, entrypoint_id } => JsUiEvent::OpenView {
|
||||
frontend,
|
||||
entrypoint_id,
|
||||
},
|
||||
IntermediateUiEvent::RunCommand { entrypoint_id } => JsUiEvent::RunCommand {
|
||||
entrypoint_id
|
||||
},
|
||||
IntermediateUiEvent::ViewEvent { widget_id, event_name, event_arguments } => {
|
||||
let event_arguments = event_arguments.into_iter()
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use serde::Deserialize;
|
|||
use common::model::PluginId;
|
||||
|
||||
use crate::dbus::DbusManagementServer;
|
||||
use crate::model::{entrypoint_to_str, PluginEntrypointType};
|
||||
use crate::plugins::data_db_repository::{Code, DataDbRepository, PluginPermissions, SavePlugin, SavePluginEntrypoint};
|
||||
|
||||
pub struct PluginLoader {
|
||||
|
|
@ -160,13 +161,17 @@ impl PluginLoader {
|
|||
|
||||
tracing::debug!("Plugin config read: {:?}", config);
|
||||
|
||||
let plugin_name = config.metadata.name;
|
||||
let plugin_name = config.gauntlet.name;
|
||||
|
||||
let entrypoints: Vec<_> = config.entrypoint
|
||||
.into_iter()
|
||||
.map(|entrypoint| SavePluginEntrypoint {
|
||||
id: entrypoint.id,
|
||||
name: entrypoint.name,
|
||||
entrypoint_type: entrypoint_to_str(match entrypoint.entrypoint_type {
|
||||
PluginConfigEntrypointTypes::Command => PluginEntrypointType::Command,
|
||||
PluginConfigEntrypointTypes::View => PluginEntrypointType::View,
|
||||
}).to_owned()
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
|
@ -203,7 +208,7 @@ struct PluginDirData {
|
|||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct PluginConfig {
|
||||
metadata: PluginConfigMetadata,
|
||||
gauntlet: PluginConfigMetadata,
|
||||
entrypoint: Vec<PluginConfigEntrypoint>,
|
||||
#[serde(default)]
|
||||
supported_system: Vec<PluginConfigSupportedSystem>,
|
||||
|
|
@ -217,6 +222,16 @@ struct PluginConfigEntrypoint {
|
|||
name: String,
|
||||
#[allow(unused)] // used when building plugin
|
||||
path: String,
|
||||
#[serde(rename = "type")]
|
||||
entrypoint_type: PluginConfigEntrypointTypes,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub enum PluginConfigEntrypointTypes {
|
||||
#[serde(rename = "command")]
|
||||
Command,
|
||||
#[serde(rename = "view")]
|
||||
View,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
use common::dbus::{DBusEntrypoint, DBusPlugin};
|
||||
use common::dbus::{DBusEntrypoint, DBusEntrypointType, DBusPlugin};
|
||||
use common::model::{EntrypointId, PluginId};
|
||||
|
||||
use crate::dirs::Dirs;
|
||||
use crate::model::{entrypoint_from_str, PluginEntrypointType};
|
||||
use crate::plugins::config_reader::ConfigReader;
|
||||
use crate::plugins::data_db_repository::{DataDbRepository};
|
||||
use crate::plugins::data_db_repository::DataDbRepository;
|
||||
use crate::plugins::js::{PluginCode, PluginCommand, PluginCommandData, PluginPermissions, PluginRuntimeData, start_plugin_runtime};
|
||||
use crate::plugins::loader::PluginLoader;
|
||||
use crate::plugins::run_status::RunStatusHolder;
|
||||
|
|
@ -70,6 +72,10 @@ impl ApplicationManager {
|
|||
enabled: entrypoint.enabled,
|
||||
entrypoint_id: entrypoint.id,
|
||||
entrypoint_name: entrypoint.name,
|
||||
entrypoint_type: match entrypoint_from_str(&entrypoint.entrypoint_type) {
|
||||
PluginEntrypointType::Command => DBusEntrypointType::Command,
|
||||
PluginEntrypointType::View => DBusEntrypointType::View,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
|
@ -219,6 +225,7 @@ impl ApplicationManager {
|
|||
.filter(|entrypoint| entrypoint.enabled)
|
||||
.map(|entrypoint| {
|
||||
SearchItem {
|
||||
entrypoint_type: entrypoint_from_str(&entrypoint.entrypoint_type),
|
||||
entrypoint_name: entrypoint.name.to_owned(),
|
||||
entrypoint_id: entrypoint.id.to_string(),
|
||||
plugin_name: plugin.name.to_owned(),
|
||||
|
|
|
|||
|
|
@ -3,12 +3,14 @@ use tantivy::collector::TopDocs;
|
|||
use tantivy::query::{AllQuery, BooleanQuery, FuzzyTermQuery, Query};
|
||||
use tantivy::schema::*;
|
||||
use tantivy::tokenizer::TokenizerManager;
|
||||
use crate::model::{entrypoint_from_str, entrypoint_to_str, PluginEntrypointType};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SearchIndex {
|
||||
index: Index,
|
||||
index_reader: IndexReader,
|
||||
|
||||
entrypoint_type: Field,
|
||||
entrypoint_name: Field,
|
||||
entrypoint_id: Field,
|
||||
plugin_name: Field,
|
||||
|
|
@ -20,6 +22,7 @@ impl SearchIndex {
|
|||
let schema = {
|
||||
let mut schema_builder = Schema::builder();
|
||||
|
||||
schema_builder.add_text_field("entrypoint_type", STORED);
|
||||
schema_builder.add_text_field("entrypoint_name", TEXT | STORED);
|
||||
schema_builder.add_text_field("entrypoint_id", STORED);
|
||||
schema_builder.add_text_field("plugin_name", TEXT | STORED);
|
||||
|
|
@ -28,6 +31,7 @@ impl SearchIndex {
|
|||
schema_builder.build()
|
||||
};
|
||||
|
||||
let entrypoint_type = schema.get_field("entrypoint_type").expect("entrypoint_type field should exist");
|
||||
let entrypoint_name = schema.get_field("entrypoint_name").expect("entrypoint_name field should exist");
|
||||
let entrypoint_id = schema.get_field("entrypoint_id").expect("entrypoint_id field should exist");
|
||||
let plugin_name = schema.get_field("plugin_name").expect("plugin_name field should exist");
|
||||
|
|
@ -43,6 +47,7 @@ impl SearchIndex {
|
|||
Ok(Self {
|
||||
index,
|
||||
index_reader,
|
||||
entrypoint_type,
|
||||
entrypoint_name,
|
||||
entrypoint_id,
|
||||
plugin_name,
|
||||
|
|
@ -55,11 +60,12 @@ impl SearchIndex {
|
|||
|
||||
index_writer.delete_all_documents()?;
|
||||
|
||||
println!("{:?}", search_items);
|
||||
tracing::debug!("Reloading search index using following data: {:?}", search_items);
|
||||
|
||||
for search_item in search_items {
|
||||
index_writer.add_document(doc!(
|
||||
self.entrypoint_name => search_item.entrypoint_name,
|
||||
self.entrypoint_type => entrypoint_to_str(search_item.entrypoint_type),
|
||||
self.entrypoint_id => search_item.entrypoint_id,
|
||||
self.plugin_name => search_item.plugin_name,
|
||||
self.plugin_id => search_item.plugin_id,
|
||||
|
|
@ -83,6 +89,7 @@ impl SearchIndex {
|
|||
SearchHandle {
|
||||
searcher,
|
||||
query_parser,
|
||||
entrypoint_type: self.entrypoint_type,
|
||||
entrypoint_name: self.entrypoint_name,
|
||||
entrypoint_id: self.entrypoint_id,
|
||||
plugin_name: self.plugin_name,
|
||||
|
|
@ -93,6 +100,7 @@ impl SearchIndex {
|
|||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SearchItem {
|
||||
pub entrypoint_type: PluginEntrypointType,
|
||||
pub entrypoint_name: String,
|
||||
pub entrypoint_id: String,
|
||||
pub plugin_name: String,
|
||||
|
|
@ -104,6 +112,7 @@ pub struct SearchHandle {
|
|||
query_parser: QueryParser,
|
||||
|
||||
entrypoint_name: Field,
|
||||
entrypoint_type: Field,
|
||||
entrypoint_id: Field,
|
||||
plugin_name: Field,
|
||||
plugin_id: Field,
|
||||
|
|
@ -155,6 +164,7 @@ impl SearchHandle {
|
|||
.expect("index should contain just searched results");
|
||||
|
||||
SearchItem {
|
||||
entrypoint_type: entrypoint_from_str(&get_str_field(&retrieved_doc, self.entrypoint_type)),
|
||||
entrypoint_name: get_str_field(&retrieved_doc, self.entrypoint_name),
|
||||
entrypoint_id: get_str_field(&retrieved_doc, self.entrypoint_id),
|
||||
plugin_name: get_str_field(&retrieved_doc, self.plugin_name),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue