Send preferences data to settings ui

This commit is contained in:
Exidex 2024-03-05 22:12:11 +01:00
parent 763ad364bb
commit da2eaf7cc2
8 changed files with 694 additions and 224 deletions

View file

@ -6,54 +6,3 @@ tonic::include_proto!("_");
pub type FrontendClient = rpc_frontend_client::RpcFrontendClient<Channel>;
pub type BackendClient = rpc_backend_client::RpcBackendClient<Channel>;
// #[derive(Debug, Clone, Serialize, Deserialize)]
// pub struct RpcSearchResult {
// pub plugin_id: String,
// pub plugin_name: String,
// pub entrypoint_id: String,
// pub entrypoint_name: String,
// pub entrypoint_type: RpcEntrypointType,
// }
// #[derive(Debug, Clone, Serialize, Deserialize)]
// pub struct RpcPlugin {
// pub plugin_id: String,
// pub plugin_name: String,
// pub enabled: bool,
// pub entrypoints: Vec<RpcEntrypoint>,
// }
// #[derive(Debug, Clone, Serialize, Deserialize)]
// pub struct RpcEntrypoint {
// pub entrypoint_id: String,
// pub entrypoint_name: String,
// pub enabled: bool,
// pub entrypoint_type: RpcEntrypointType,
// }
//
// #[derive(Debug, Clone, Deserialize, Serialize)]
// pub struct RpcUiWidget {
// pub widget_id: RpcUiWidgetId,
// pub widget_type: String,
// pub widget_properties: HashMap<String, RpcUiPropertyValue>,
// pub widget_children: Vec<RpcUiWidget>,
// }
// #[derive(Debug, Clone, Deserialize, Serialize)]
// pub struct RpcEventRenderView {
// pub frontend: String,
// pub entrypoint_id: String,
// }
//
// #[derive(Debug, Clone, Deserialize, Serialize)]
// pub struct RpcEventRunCommand {
// pub entrypoint_id: String,
// }
// #[derive(Debug, Clone, Serialize, Deserialize)]
// pub enum RpcEntrypointType {
// Command,
// View,
// InlineView,
// }

View file

@ -3,7 +3,7 @@ use std::collections::{HashMap, HashSet};
use std::rc::Rc;
use std::time::Duration;
use iced::{Alignment, Application, Command, Element, executor, font, futures, Length, Padding, Renderer, Settings, Size, Subscription, theme, Theme, time, window, color};
use iced::{Alignment, Application, color, Command, Element, executor, font, futures, Length, Padding, Renderer, Settings, Size, Subscription, theme, Theme, time, window};
use iced::theme::Palette;
use iced::widget::{button, checkbox, column, container, horizontal_space, row, scrollable, Space, text, text_input, vertical_rule};
use iced_aw::graphics::icons;
@ -11,8 +11,9 @@ use iced_table::table;
use tonic::Request;
use common::model::{EntrypointId, PluginId};
use common::rpc::{BackendClient, RpcDownloadPluginRequest, RpcDownloadStatus, RpcDownloadStatusRequest, RpcEntrypointType, RpcPluginsRequest, RpcSetEntrypointStateRequest, RpcSetPluginStateRequest};
use common::rpc::{BackendClient, RpcDownloadPluginRequest, RpcDownloadStatus, RpcDownloadStatusRequest, RpcEntrypointType, RpcPluginPreference, RpcPluginPreferenceUserData, RpcPluginPreferenceValueType, RpcPluginsRequest, RpcSetEntrypointStateRequest, RpcSetPluginStateRequest};
use common::rpc::rpc_backend_client::RpcBackendClient;
use common::rpc::rpc_ui_property_value::Value;
pub fn run() {
ManagementAppModel::run(Settings {
@ -94,6 +95,8 @@ struct Plugin {
show_entrypoints: bool,
enabled: bool,
entrypoints: HashMap<EntrypointId, Entrypoint>,
preferences: HashMap<String, PluginPreference>,
preferences_user_data: HashMap<String, PluginPreferenceUserData>,
}
#[derive(Debug, Clone)]
@ -102,6 +105,8 @@ struct Entrypoint {
entrypoint_name: String,
entrypoint_type: EntrypointType,
enabled: bool,
preferences: HashMap<String, PluginPreference>,
preferences_user_data: HashMap<String, PluginPreferenceUserData>,
}
#[derive(Debug, Clone)]
@ -111,6 +116,72 @@ pub enum EntrypointType {
InlineView,
}
#[derive(Debug, Clone)]
pub enum PluginPreferenceUserData {
Number {
value: Option<f64>,
},
String {
value: Option<String>,
},
Enum {
value: Option<String>,
},
Bool {
value: Option<bool>,
},
ListOfStrings {
value: Option<Vec<String>>,
},
ListOfNumbers {
value: Option<Vec<f64>>,
},
ListOfEnums {
value: Option<Vec<String>>,
}
}
#[derive(Debug, Clone)]
pub enum PluginPreference {
Number {
default: Option<f64>,
description: String,
},
String {
default: Option<String>,
description: String,
},
Enum {
default: Option<String>,
description: String,
enum_values: Vec<PreferenceEnumValue>,
},
Bool {
default: Option<bool>,
description: String,
},
ListOfStrings {
default: Option<Vec<String>>,
description: String,
},
ListOfNumbers {
default: Option<Vec<f64>>,
description: String,
},
ListOfEnums {
default: Option<Vec<String>>,
enum_values: Vec<PreferenceEnumValue>,
description: String,
}
}
#[derive(Debug, Clone)]
pub struct PreferenceEnumValue {
pub label: String,
pub value: String,
}
impl Application for ManagementAppModel {
type Executor = executor::Default;
type Message = ManagementAppMsg;
@ -753,7 +824,13 @@ async fn reload_plugins(mut backend_client: BackendClient) -> HashMap<PluginId,
enabled: entrypoint.enabled,
entrypoint_id: id.clone(),
entrypoint_name: entrypoint.entrypoint_name.clone(),
entrypoint_type
entrypoint_type,
preferences: entrypoint.preferences.into_iter()
.map(|(key, value)| (key, plugin_preference_from_grpc(value)))
.collect(),
preferences_user_data: entrypoint.preferences_user_data.into_iter()
.map(|(key, value)| (key, plugin_preference_user_data_from_grpc(value)))
.collect(),
};
(id, entrypoint)
})
@ -766,9 +843,276 @@ async fn reload_plugins(mut backend_client: BackendClient) -> HashMap<PluginId,
show_entrypoints: true,
enabled: plugin.enabled,
entrypoints,
};
preferences: plugin.preferences.into_iter()
.map(|(key, value)| (key, plugin_preference_from_grpc(value)))
.collect(),
preferences_user_data: plugin.preferences_user_data.into_iter()
.map(|(key, value)| (key, plugin_preference_user_data_from_grpc(value)))
.collect(),};
(id, plugin)
})
.collect()
}
}
fn plugin_preference_from_grpc(value: RpcPluginPreference) -> PluginPreference {
let value_type: RpcPluginPreferenceValueType = value.r#type.try_into().unwrap();
match value_type {
RpcPluginPreferenceValueType::Number => {
let default = value.default
.map(|value| {
match value.value.unwrap() {
Value::Number(value) => value,
_ => unreachable!()
}
});
PluginPreference::Number {
default,
description: value.description,
}
}
RpcPluginPreferenceValueType::String => {
let default = value.default
.map(|value| {
match value.value.unwrap() {
Value::String(value) => value,
_ => unreachable!()
}
});
PluginPreference::String {
default,
description: value.description,
}
}
RpcPluginPreferenceValueType::Enum => {
let default = value.default
.map(|value| {
match value.value.unwrap() {
Value::String(value) => value,
_ => unreachable!()
}
});
PluginPreference::Enum {
default,
description: value.description,
enum_values: value.enum_values.into_iter()
.map(|value| PreferenceEnumValue { label: value.label, value: value.value })
.collect()
}
}
RpcPluginPreferenceValueType::Bool => {
let default = value.default
.map(|value| {
match value.value.unwrap() {
Value::Bool(value) => value,
_ => unreachable!()
}
});
PluginPreference::Bool {
default,
description: value.description,
}
}
RpcPluginPreferenceValueType::ListOfStrings => {
let default_list = match value.default_list_exists {
true => {
let default_list = value.default_list
.into_iter()
.flat_map(|value| value.value.map(|value| {
match value {
Value::String(value) => value,
_ => unreachable!()
}
}))
.collect();
Some(default_list)
},
false => None
};
PluginPreference::ListOfStrings {
default: default_list,
description: value.description,
}
}
RpcPluginPreferenceValueType::ListOfNumbers => {
let default_list = match value.default_list_exists {
true => {
let default_list = value.default_list
.into_iter()
.flat_map(|value| value.value.map(|value| {
match value {
Value::Number(value) => value,
_ => unreachable!()
}
}))
.collect();
Some(default_list)
},
false => None
};
PluginPreference::ListOfNumbers {
default: default_list,
description: value.description,
}
}
RpcPluginPreferenceValueType::ListOfEnums => {
let default_list = match value.default_list_exists {
true => {
let default_list = value.default_list
.into_iter()
.flat_map(|value| value.value.map(|value| {
match value {
Value::String(value) => value,
_ => unreachable!()
}
}))
.collect();
Some(default_list)
},
false => None
};
PluginPreference::ListOfEnums {
default: default_list,
enum_values: value.enum_values.into_iter()
.map(|value| PreferenceEnumValue { label: value.label, value: value.value })
.collect(),
description: value.description,
}
}
}
}
fn plugin_preference_user_data_from_grpc(value: RpcPluginPreferenceUserData) -> PluginPreferenceUserData {
let value_type: RpcPluginPreferenceValueType = value.r#type.try_into().unwrap();
match value_type {
RpcPluginPreferenceValueType::Number => {
let value = value.value
.map(|value| {
match value.value.unwrap() {
Value::Number(value) => value,
_ => unreachable!()
}
});
PluginPreferenceUserData::Number {
value
}
}
RpcPluginPreferenceValueType::String => {
let value = value.value
.map(|value| {
match value.value.unwrap() {
Value::String(value) => value,
_ => unreachable!()
}
});
PluginPreferenceUserData::String {
value
}
}
RpcPluginPreferenceValueType::Enum => {
let value = value.value
.map(|value| {
match value.value.unwrap() {
Value::String(value) => value,
_ => unreachable!()
}
});
PluginPreferenceUserData::Enum {
value
}
}
RpcPluginPreferenceValueType::Bool => {
let value = value.value
.map(|value| {
match value.value.unwrap() {
Value::Bool(value) => value,
_ => unreachable!()
}
});
PluginPreferenceUserData::Bool {
value
}
}
RpcPluginPreferenceValueType::ListOfStrings => {
let value = match value.value_list_exists {
true => {
let value_list = value.value_list
.into_iter()
.flat_map(|value| value.value.map(|value| {
match value {
Value::String(value) => value,
_ => unreachable!()
}
}))
.collect();
Some(value_list)
},
false => None
};
PluginPreferenceUserData::ListOfStrings {
value
}
}
RpcPluginPreferenceValueType::ListOfNumbers => {
let value = match value.value_list_exists {
true => {
let value_list = value.value_list
.into_iter()
.flat_map(|value| value.value.map(|value| {
match value {
Value::Number(value) => value,
_ => unreachable!()
}
}))
.collect();
Some(value_list)
},
false => None
};
PluginPreferenceUserData::ListOfNumbers {
value
}
}
RpcPluginPreferenceValueType::ListOfEnums => {
let value = match value.value_list_exists {
true => {
let value_list = value.value_list
.into_iter()
.flat_map(|value| value.value.map(|value| {
match value {
Value::String(value) => value,
_ => unreachable!()
}
}))
.collect();
Some(value_list)
},
false => None
};
PluginPreferenceUserData::ListOfEnums {
value
}
}
}
}

View file

@ -2,7 +2,7 @@ use serde::Deserialize;
use tracing::{error, info};
use crate::dirs::Dirs;
use crate::plugins::data_db_repository::{DataDbRepository, SavePendingPlugin};
use crate::plugins::data_db_repository::{DataDbRepository, DbWritePendingPlugin};
pub struct ConfigReader {
dirs: Dirs,
@ -25,7 +25,7 @@ impl ConfigReader {
if !exists {
let pending = self.repository.is_plugin_pending(&plugin.id).await?;
if !pending {
let pending_plugin = SavePendingPlugin {
let pending_plugin = DbWritePendingPlugin {
id: plugin.id
};
self.repository.save_pending_plugin(pending_plugin).await?
@ -62,7 +62,7 @@ impl ConfigReader {
#[derive(Debug, Deserialize, Default)]
pub struct ApplicationConfig {
// #[serde(default)]
// #[serde(default)] // TODO
// configuration_mode: ConfigurationModeConfig,
#[serde(default)]
plugins: Vec<PluginEntryConfig>,

View file

@ -12,7 +12,6 @@ use sqlx::sqlite::SqliteConnectOptions;
use sqlx::types::Json;
use crate::dirs::Dirs;
use crate::plugins::loader::EnumValue;
static MIGRATOR: Migrator = sqlx::migrate!("./db_migrations");
@ -21,37 +20,24 @@ pub struct DataDbRepository {
pool: Pool<Sqlite>,
}
pub struct GetListPlugin {
pub id: String,
pub name: String,
pub enabled: bool,
pub code: Code,
pub entrypoints: Vec<GetPluginEntrypoint>,
}
#[derive(sqlx::FromRow)]
pub struct GetPlugin {
pub struct DbReadPlugin {
pub id: String,
pub name: String,
pub enabled: bool,
#[sqlx(json)]
pub code: Code,
pub code: DbCode,
#[sqlx(json)]
pub permissions: PluginPermissions,
pub permissions: DbPluginPermissions,
pub from_config: bool,
#[sqlx(json)]
pub preferences: HashMap<String, PluginPreference>,
pub preferences: HashMap<String, DbPluginPreference>,
#[sqlx(json)]
pub preferences_user_data: HashMap<String, PluginPreferenceUserData>,
pub preferences_user_data: HashMap<String, DbPluginPreferenceUserData>,
}
#[derive(sqlx::FromRow)]
pub struct GetPendingPlugin {
pub id: String,
}
#[derive(sqlx::FromRow)]
pub struct GetPluginEntrypoint {
pub struct DbReadPluginEntrypoint {
pub id: String,
pub plugin_id: String,
pub name: String,
@ -59,54 +45,38 @@ pub struct GetPluginEntrypoint {
#[sqlx(rename = "type")]
pub entrypoint_type: String,
#[sqlx(json)]
pub preferences: HashMap<String, PluginPreference>,
pub preferences: HashMap<String, DbPluginPreference>,
#[sqlx(json)]
pub preferences_user_data: HashMap<String, PluginPreferenceUserData>,
pub preferences_user_data: HashMap<String, DbPluginPreferenceUserData>,
}
#[derive(Deserialize, Serialize)]
pub struct Code {
pub struct DbCode {
pub js: HashMap<String, String>,
}
#[derive(sqlx::FromRow)]
pub struct GetPluginPreferences {
#[sqlx(json)]
pub preferences: HashMap<String, PluginPreference>,
#[sqlx(json)]
pub preferences_user_data: HashMap<String, PluginPreferenceUserData>,
}
#[derive(sqlx::FromRow)]
pub struct GetPluginEntrypointPreferences {
#[sqlx(json)]
pub preferences: HashMap<String, PluginPreference>,
#[sqlx(json)]
pub preferences_user_data: HashMap<String, PluginPreferenceUserData>,
}
pub struct SavePlugin {
pub struct DbWritePlugin {
pub id: String,
pub name: String,
pub enabled: bool,
pub code: Code,
pub entrypoints: Vec<SavePluginEntrypoint>,
pub permissions: PluginPermissions,
pub code: DbCode,
pub entrypoints: Vec<DbWritePluginEntrypoint>,
pub permissions: DbPluginPermissions,
pub from_config: bool,
pub preferences: HashMap<String, PluginPreference>,
pub preferences_user_data: HashMap<String, PluginPreferenceUserData>,
pub preferences: HashMap<String, DbPluginPreference>,
pub preferences_user_data: HashMap<String, DbPluginPreferenceUserData>,
}
pub struct SavePluginEntrypoint {
pub struct DbWritePluginEntrypoint {
pub id: String,
pub name: String,
pub entrypoint_type: String,
pub preferences: HashMap<String, PluginPreference>,
pub preferences_user_data: HashMap<String, PluginPreferenceUserData>,
pub preferences: HashMap<String, DbPluginPreference>,
pub preferences_user_data: HashMap<String, DbPluginPreferenceUserData>,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct PluginPermissions {
pub struct DbPluginPermissions {
pub environment: Vec<String>,
pub high_resolution_time: bool,
pub network: Vec<String>,
@ -119,7 +89,7 @@ pub struct PluginPermissions {
#[derive(Debug, Deserialize, Serialize)]
#[serde(tag = "type")]
pub enum PluginPreferenceUserData {
pub enum DbPluginPreferenceUserData {
#[serde(rename = "number")]
Number {
value: Option<f64>,
@ -152,7 +122,7 @@ pub enum PluginPreferenceUserData {
#[derive(Debug, Deserialize, Serialize)]
#[serde(tag = "type")]
pub enum PluginPreference {
pub enum DbPluginPreference {
#[serde(rename = "number")]
Number {
default: Option<f64>,
@ -167,7 +137,7 @@ pub enum PluginPreference {
Enum {
default: Option<String>,
description: String,
enum_values: Vec<EnumValue>,
enum_values: Vec<DbPreferenceEnumValue>,
},
#[serde(rename = "bool")]
Bool {
@ -187,21 +157,27 @@ pub enum PluginPreference {
#[serde(rename = "list_of_enums")]
ListOfEnums {
default: Option<Vec<String>>,
enum_values: Vec<EnumValue>,
enum_values: Vec<DbPreferenceEnumValue>,
description: String,
}
}
pub struct SavePendingPlugin {
#[derive(Debug, Deserialize, Serialize)]
pub struct DbPreferenceEnumValue {
pub label: String,
pub value: String,
}
#[derive(sqlx::FromRow)]
pub struct DbReadPendingPlugin {
pub id: String,
}
#[derive(sqlx::FromRow)]
struct PluginEnabled {
pub enabled: bool,
pub struct DbWritePendingPlugin {
pub id: String,
}
impl DataDbRepository {
pub async fn new(dirs: Dirs) -> anyhow::Result<Self> {
let conn = SqliteConnectOptions::new()
@ -222,33 +198,34 @@ impl DataDbRepository {
})
}
pub async fn list_plugins(&self) -> anyhow::Result<Vec<GetListPlugin>> {
pub async fn list_plugins(&self) -> anyhow::Result<Vec<DbReadPlugin>> {
// language=SQLite
let plugins = sqlx::query_as::<_, GetPlugin>("SELECT * FROM plugin")
let plugins = sqlx::query_as::<_, DbReadPlugin>("SELECT * FROM plugin")
.fetch_all(&self.pool)
.await?;
Ok(plugins)
}
pub async fn list_plugins_and_entrypoints(&self) -> anyhow::Result<Vec<(DbReadPlugin, Vec<DbReadPluginEntrypoint>)>> {
// language=SQLite
let plugins = self.list_plugins().await?;
let result = futures::stream::iter(plugins)
.then(|plugin| async move {
let entrypoints = self.get_entrypoints_by_plugin_id(&plugin.id).await?;
Ok::<GetListPlugin, AnyError>(GetListPlugin {
id: plugin.id,
name: plugin.name,
enabled: plugin.enabled,
code: plugin.code,
entrypoints,
})
Ok::<(DbReadPlugin, Vec<DbReadPluginEntrypoint>), AnyError>((plugin, entrypoints))
})
.try_collect::<Vec<GetListPlugin>>()
.try_collect::<Vec<(DbReadPlugin, Vec<DbReadPluginEntrypoint>)>>()
.await?;
Ok(result)
}
pub async fn get_plugin_by_id(&self, plugin_id: &str) -> anyhow::Result<GetPlugin> {
pub async fn get_plugin_by_id(&self, plugin_id: &str) -> anyhow::Result<DbReadPlugin> {
// language=SQLite
let result = sqlx::query_as::<_, GetPlugin>("SELECT * FROM plugin WHERE id = ?1")
let result = sqlx::query_as::<_, DbReadPlugin>("SELECT * FROM plugin WHERE id = ?1")
.bind(plugin_id)
.fetch_one(&self.pool)
.await?;
@ -256,9 +233,9 @@ impl DataDbRepository {
Ok(result)
}
pub async fn get_entrypoints_by_plugin_id(&self, plugin_id: &str) -> anyhow::Result<Vec<GetPluginEntrypoint>> {
pub async fn get_entrypoints_by_plugin_id(&self, plugin_id: &str) -> anyhow::Result<Vec<DbReadPluginEntrypoint>> {
// language=SQLite
let result = sqlx::query_as::<_, GetPluginEntrypoint>("SELECT * FROM plugin_entrypoint WHERE plugin_id = ?1")
let result = sqlx::query_as::<_, DbReadPluginEntrypoint>("SELECT * FROM plugin_entrypoint WHERE plugin_id = ?1")
.bind(plugin_id)
.fetch_all(&self.pool)
.await?;
@ -266,6 +243,17 @@ impl DataDbRepository {
Ok(result)
}
pub async fn get_entrypoint_by_id(&self, plugin_id: &str, entrypoint_id: &str) -> anyhow::Result<DbReadPluginEntrypoint> {
// language=SQLite
let result = sqlx::query_as::<_, DbReadPluginEntrypoint>("SELECT * FROM plugin_entrypoint WHERE id = ?1 AND plugin_id = ?2")
.bind(entrypoint_id)
.bind(plugin_id)
.fetch_one(&self.pool)
.await?;
Ok(result)
}
pub async fn get_inline_view_entrypoint_id_for_plugin(&self, plugin_id: &str) -> anyhow::Result<Option<String>> {
// language=SQLite
let entrypoint_id = sqlx::query_as::<_, (String, )>("SELECT id FROM plugin_entrypoint WHERE plugin_id = ?1 AND type = 'inline-view'")
@ -277,9 +265,9 @@ impl DataDbRepository {
Ok(entrypoint_id)
}
pub async fn list_pending_plugins(&self) -> anyhow::Result<Vec<GetPendingPlugin>> {
pub async fn list_pending_plugins(&self) -> anyhow::Result<Vec<DbReadPendingPlugin>> {
// language=SQLite
let plugins = sqlx::query_as::<_, GetPendingPlugin>("SELECT * FROM pending_plugin")
let plugins = sqlx::query_as::<_, DbReadPendingPlugin>("SELECT * FROM pending_plugin")
.fetch_all(&self.pool)
.await?;
@ -307,8 +295,13 @@ impl DataDbRepository {
}
pub async fn is_plugin_enabled(&self, plugin_id: &str) -> anyhow::Result<bool> {
#[derive(sqlx::FromRow)]
struct DbReadPluginEnabled {
pub enabled: bool,
}
// language=SQLite
let result = sqlx::query_as::<_, PluginEnabled>("SELECT enabled FROM plugin WHERE id = ?1")
let result = sqlx::query_as::<_, DbReadPluginEnabled>("SELECT enabled FROM plugin WHERE id = ?1")
.bind(plugin_id)
.fetch_one(&self.pool)
.await?;
@ -316,27 +309,6 @@ impl DataDbRepository {
Ok(result.enabled)
}
pub async fn get_plugin_preferences(&self, plugin_id: &str) -> anyhow::Result<GetPluginPreferences> {
// language=SQLite
let result = sqlx::query_as::<_, GetPluginPreferences>("SELECT * FROM plugin WHERE id = ?1")
.bind(plugin_id)
.fetch_one(&self.pool)
.await?;
Ok(result)
}
pub async fn get_plugin_entrypoint_preferences(&self, plugin_id: &str, entrypoint_id: &str) -> anyhow::Result<GetPluginEntrypointPreferences> {
// language=SQLite
let result = sqlx::query_as::<_, GetPluginEntrypointPreferences>("SELECT * FROM plugin_entrypoint WHERE id = ?1 AND plugin_id = ?2")
.bind(entrypoint_id)
.bind(plugin_id)
.fetch_one(&self.pool)
.await?;
Ok(result)
}
pub async fn set_plugin_enabled(&self, plugin_id: &str, enabled: bool) -> anyhow::Result<()> {
// language=SQLite
sqlx::query("UPDATE plugin SET enabled = ?1 WHERE id = ?2")
@ -360,7 +332,7 @@ impl DataDbRepository {
Ok(())
}
pub async fn save_pending_plugin(&self, plugin: SavePendingPlugin) -> anyhow::Result<()> {
pub async fn save_pending_plugin(&self, plugin: DbWritePendingPlugin) -> anyhow::Result<()> {
// language=SQLite
sqlx::query("INSERT INTO pending_plugin VALUES(?1)")
.bind(&plugin.id)
@ -379,7 +351,7 @@ impl DataDbRepository {
Ok(())
}
pub async fn save_plugin(&self, plugin: SavePlugin) -> anyhow::Result<()> {
pub async fn save_plugin(&self, plugin: DbWritePlugin) -> anyhow::Result<()> {
let mut tx = self.pool.begin().await?;
// language=SQLite

View file

@ -27,7 +27,7 @@ use common::rpc::rpc_frontend_server::RpcFrontend;
use component_model::{Children, Component, create_component_model, PropertyType};
use crate::model::{from_rpc_to_intermediate_value, IntermediateUiEvent, IntermediateUiWidget, JsPropertyValue, JsRenderLocation, JsUiEvent, JsUiRequestData, JsUiResponseData, JsUiWidget, PreferenceUserData, UiWidgetId};
use crate::plugins::data_db_repository::{DataDbRepository, GetPluginEntrypointPreferences, GetPluginPreferences, PluginPreference, PluginPreferenceUserData};
use crate::plugins::data_db_repository::{DataDbRepository, DbPluginPreference, DbPluginPreferenceUserData, DbReadPlugin, DbReadPluginEntrypoint};
use crate::plugins::run_status::RunStatusGuard;
pub struct PluginRuntimeData {
@ -492,8 +492,8 @@ fn get_plugin_preferences(state: Rc<RefCell<OpState>>) -> anyhow::Result<HashMap
};
block_on(async {
let GetPluginPreferences { preferences, preferences_user_data } = repository
.get_plugin_preferences(&plugin_id.to_string())
let DbReadPlugin { preferences, preferences_user_data, .. } = repository
.get_plugin_by_id(&plugin_id.to_string())
.await?;
Ok(preferences_to_js(preferences, preferences_user_data))
@ -519,8 +519,8 @@ fn get_entrypoint_preferences(state: Rc<RefCell<OpState>>, entrypoint_id: &str)
};
block_on(async {
let GetPluginEntrypointPreferences { preferences, preferences_user_data } = repository
.get_plugin_entrypoint_preferences(&plugin_id.to_string(), entrypoint_id)
let DbReadPluginEntrypoint { preferences, preferences_user_data, .. } = repository
.get_entrypoint_by_id(&plugin_id.to_string(), entrypoint_id)
.await?;
Ok(preferences_to_js(preferences, preferences_user_data))
@ -528,31 +528,31 @@ fn get_entrypoint_preferences(state: Rc<RefCell<OpState>>, entrypoint_id: &str)
}
fn preferences_to_js(
preferences: HashMap<String, PluginPreference>,
mut preferences_user_data: HashMap<String, PluginPreferenceUserData>
preferences: HashMap<String, DbPluginPreference>,
mut preferences_user_data: HashMap<String, DbPluginPreferenceUserData>
) -> HashMap<String, PreferenceUserData> {
preferences.into_iter()
.map(|(name, preference)| {
let user_data = match preferences_user_data.remove(&name) {
None => {
match preference {
PluginPreference::Number { default, .. } => PreferenceUserData::Number(default),
PluginPreference::String { default, .. } => PreferenceUserData::String(default),
PluginPreference::Enum { default, .. } => PreferenceUserData::String(default),
PluginPreference::Bool { default, .. } => PreferenceUserData::Bool(default),
PluginPreference::ListOfStrings { default, .. } => PreferenceUserData::ListOfStrings(default.unwrap_or(vec![])),
PluginPreference::ListOfNumbers { default, .. } => PreferenceUserData::ListOfNumbers(default.unwrap_or(vec![])),
PluginPreference::ListOfEnums { default, .. } => PreferenceUserData::ListOfStrings(default.unwrap_or(vec![])),
DbPluginPreference::Number { default, .. } => PreferenceUserData::Number(default),
DbPluginPreference::String { default, .. } => PreferenceUserData::String(default),
DbPluginPreference::Enum { default, .. } => PreferenceUserData::String(default),
DbPluginPreference::Bool { default, .. } => PreferenceUserData::Bool(default),
DbPluginPreference::ListOfStrings { default, .. } => PreferenceUserData::ListOfStrings(default.unwrap_or(vec![])),
DbPluginPreference::ListOfNumbers { default, .. } => PreferenceUserData::ListOfNumbers(default.unwrap_or(vec![])),
DbPluginPreference::ListOfEnums { default, .. } => PreferenceUserData::ListOfStrings(default.unwrap_or(vec![])),
}
}
Some(user_data) => match user_data {
PluginPreferenceUserData::Number { value } => PreferenceUserData::Number(value),
PluginPreferenceUserData::String { value } => PreferenceUserData::String(value),
PluginPreferenceUserData::Enum { value } => PreferenceUserData::String(value),
PluginPreferenceUserData::Bool { value } => PreferenceUserData::Bool(value),
PluginPreferenceUserData::ListOfStrings { value } => PreferenceUserData::ListOfStrings(value.unwrap_or(vec![])),
PluginPreferenceUserData::ListOfNumbers { value } => PreferenceUserData::ListOfNumbers(value.unwrap_or(vec![])),
PluginPreferenceUserData::ListOfEnums { value } => PreferenceUserData::ListOfStrings(value.unwrap_or(vec![])),
DbPluginPreferenceUserData::Number { value } => PreferenceUserData::Number(value),
DbPluginPreferenceUserData::String { value } => PreferenceUserData::String(value),
DbPluginPreferenceUserData::Enum { value } => PreferenceUserData::String(value),
DbPluginPreferenceUserData::Bool { value } => PreferenceUserData::Bool(value),
DbPluginPreferenceUserData::ListOfStrings { value } => PreferenceUserData::ListOfStrings(value.unwrap_or(vec![])),
DbPluginPreferenceUserData::ListOfNumbers { value } => PreferenceUserData::ListOfNumbers(value.unwrap_or(vec![])),
DbPluginPreferenceUserData::ListOfEnums { value } => PreferenceUserData::ListOfStrings(value.unwrap_or(vec![])),
}
};

View file

@ -12,7 +12,7 @@ use serde::{Deserialize, Serialize};
use common::model::{DownloadStatus, PluginId};
use crate::model::{entrypoint_to_str, PluginEntrypointType};
use crate::plugins::data_db_repository::{Code, DataDbRepository, PluginPermissions, PluginPreference, PluginPreferenceUserData, SavePlugin, SavePluginEntrypoint};
use crate::plugins::data_db_repository::{DbCode, DataDbRepository, DbPluginPermissions, DbPluginPreference, DbPluginPreferenceUserData, DbWritePlugin, DbWritePluginEntrypoint, DbPreferenceEnumValue};
use crate::plugins::download_status::DownloadStatusHolder;
pub struct PluginLoader {
@ -47,7 +47,7 @@ impl PluginLoader {
let plugin_data = PluginLoader::read_plugin_dir(temp_dir.path(), plugin_id.clone())
.await?;
data_db_repository.save_plugin(SavePlugin {
data_db_repository.save_plugin(DbWritePlugin {
id: plugin_data.id,
name: plugin_data.name,
enabled: false,
@ -83,7 +83,7 @@ impl PluginLoader {
self.db_repository.remove_plugin(&plugin_data.id).await?
}
self.db_repository.save_plugin(SavePlugin {
self.db_repository.save_plugin(DbWritePlugin {
id: plugin_data.id,
name: plugin_data.name,
enabled: true,
@ -125,7 +125,7 @@ impl PluginLoader {
Ok(())
}
async fn read_plugin_dir(plugin_dir: &Path, plugin_id: PluginId) -> anyhow::Result<PluginDirData> {
async fn read_plugin_dir(plugin_dir: &Path, plugin_id: PluginId) -> anyhow::Result<PluginDownloadData> {
let js_dir = plugin_dir.join("js");
let js_dir_context = js_dir.display().to_string();
@ -161,7 +161,7 @@ impl PluginLoader {
let entrypoints: Vec<_> = plugin_manifest.entrypoint
.into_iter()
.map(|entrypoint| SavePluginEntrypoint {
.map(|entrypoint| DbWritePluginEntrypoint {
id: entrypoint.id,
name: entrypoint.name,
entrypoint_type: entrypoint_to_str(match entrypoint.entrypoint_type {
@ -172,13 +172,25 @@ impl PluginLoader {
preferences: entrypoint.preferences
.into_iter()
.map(|preference| match preference {
PluginManifestPreference::Number { name, default, description } => (name, PluginPreference::Number { default, description }),
PluginManifestPreference::String { name, default, description } => (name, PluginPreference::String { default, description }),
PluginManifestPreference::Enum { name, default, description, enum_values } => (name, PluginPreference::Enum { default, description, enum_values }),
PluginManifestPreference::Bool { name, default, description } => (name, PluginPreference::Bool { default, description }),
PluginManifestPreference::ListOfStrings { name, default, description } => (name, PluginPreference::ListOfStrings { default, description }),
PluginManifestPreference::ListOfNumbers { name, default, description } => (name, PluginPreference::ListOfNumbers { default, description }),
PluginManifestPreference::ListOfEnums { name, default, description, enum_values } => (name, PluginPreference::ListOfEnums { default, description, enum_values }),
PluginManifestPreference::Number { name, default, description } => (name, DbPluginPreference::Number { default, description }),
PluginManifestPreference::String { name, default, description } => (name, DbPluginPreference::String { default, description }),
PluginManifestPreference::Enum { name, default, description, enum_values } => {
let enum_values = enum_values.into_iter()
.map(|PluginManifestPreferenceEnumValue { label, value } | DbPreferenceEnumValue { label, value })
.collect();
(name, DbPluginPreference::Enum { default, description, enum_values })
},
PluginManifestPreference::Bool { name, default, description } => (name, DbPluginPreference::Bool { default, description }),
PluginManifestPreference::ListOfStrings { name, default, description } => (name, DbPluginPreference::ListOfStrings { default, description }),
PluginManifestPreference::ListOfNumbers { name, default, description } => (name, DbPluginPreference::ListOfNumbers { default, description }),
PluginManifestPreference::ListOfEnums { name, default, description, enum_values } => {
let enum_values = enum_values.into_iter()
.map(|PluginManifestPreferenceEnumValue { label, value } | DbPreferenceEnumValue { label, value })
.collect();
(name, DbPluginPreference::ListOfEnums { default, description, enum_values })
},
})
.collect(),
preferences_user_data: HashMap::new(),
@ -188,17 +200,29 @@ impl PluginLoader {
let plugin_preferences = plugin_manifest.preferences
.into_iter()
.map(|preference| match preference {
PluginManifestPreference::Number { name, default, description } => (name, PluginPreference::Number { default, description }),
PluginManifestPreference::String { name, default, description } => (name, PluginPreference::String { default, description }),
PluginManifestPreference::Enum { name, default, description, enum_values } => (name, PluginPreference::Enum { default, description, enum_values }),
PluginManifestPreference::Bool { name, default, description } => (name, PluginPreference::Bool { default, description }),
PluginManifestPreference::ListOfStrings { name, default, description } => (name, PluginPreference::ListOfStrings { default, description }),
PluginManifestPreference::ListOfNumbers { name, default, description } => (name, PluginPreference::ListOfNumbers { default, description }),
PluginManifestPreference::ListOfEnums { name, default, description, enum_values } => (name, PluginPreference::ListOfEnums { default, description, enum_values }),
PluginManifestPreference::Number { name, default, description } => (name, DbPluginPreference::Number { default, description }),
PluginManifestPreference::String { name, default, description } => (name, DbPluginPreference::String { default, description }),
PluginManifestPreference::Enum { name, default, description, enum_values } => {
let enum_values = enum_values.into_iter()
.map(|PluginManifestPreferenceEnumValue { label, value } | DbPreferenceEnumValue { label, value })
.collect();
(name, DbPluginPreference::Enum { default, description, enum_values })
},
PluginManifestPreference::Bool { name, default, description } => (name, DbPluginPreference::Bool { default, description }),
PluginManifestPreference::ListOfStrings { name, default, description } => (name, DbPluginPreference::ListOfStrings { default, description }),
PluginManifestPreference::ListOfNumbers { name, default, description } => (name, DbPluginPreference::ListOfNumbers { default, description }),
PluginManifestPreference::ListOfEnums { name, default, description, enum_values } => {
let enum_values = enum_values.into_iter()
.map(|PluginManifestPreferenceEnumValue { label, value } | DbPreferenceEnumValue { label, value })
.collect();
(name, DbPluginPreference::ListOfEnums { default, description, enum_values })
},
})
.collect();
let permissions = PluginPermissions {
let permissions = DbPluginPermissions {
environment: plugin_manifest.permissions.environment,
high_resolution_time: plugin_manifest.permissions.high_resolution_time,
network: plugin_manifest.permissions.network,
@ -209,10 +233,10 @@ impl PluginLoader {
system: plugin_manifest.permissions.system,
};
Ok(PluginDirData {
Ok(PluginDownloadData {
id: plugin_id.to_string(),
name: plugin_name,
code: Code {
code: DbCode {
js
},
entrypoints,
@ -223,14 +247,14 @@ impl PluginLoader {
}
}
struct PluginDirData {
struct PluginDownloadData {
pub id: String,
pub name: String,
pub code: Code,
pub entrypoints: Vec<SavePluginEntrypoint>,
pub permissions: PluginPermissions,
pub preferences: HashMap<String, PluginPreference>,
pub preferences_user_data: HashMap<String, PluginPreferenceUserData>,
pub code: DbCode,
pub entrypoints: Vec<DbWritePluginEntrypoint>,
pub permissions: DbPluginPermissions,
pub preferences: HashMap<String, DbPluginPreference>,
pub preferences_user_data: HashMap<String, DbPluginPreferenceUserData>,
}
#[derive(Debug, Deserialize)]
@ -277,7 +301,7 @@ enum PluginManifestPreference {
name: String,
default: Option<String>,
description: String,
enum_values: Vec<EnumValue>,
enum_values: Vec<PluginManifestPreferenceEnumValue>,
},
#[serde(rename = "bool")]
Bool {
@ -301,15 +325,15 @@ enum PluginManifestPreference {
ListOfEnums {
name: String,
default: Option<Vec<String>>,
enum_values: Vec<EnumValue>,
enum_values: Vec<PluginManifestPreferenceEnumValue>,
description: String,
}
}
#[derive(Debug, Deserialize, Serialize)]
pub struct EnumValue {
label: String,
value: String,
pub struct PluginManifestPreferenceEnumValue {
pub label: String,
pub value: String,
}
#[derive(Debug, Deserialize)]

View file

@ -1,11 +1,11 @@
use std::collections::HashMap;
use common::rpc::{RpcEntrypoint, RpcEntrypointType, RpcPlugin};
use common::rpc::{rpc_ui_property_value, RpcEntrypoint, RpcEntrypointType, RpcEnumValue, RpcPlugin, RpcPluginPreference, RpcPluginPreferenceUserData, RpcPluginPreferenceValueType, RpcUiPropertyValue};
use common::model::{DownloadStatus, EntrypointId, PluginId, PropertyValue};
use crate::dirs::Dirs;
use crate::model::{entrypoint_from_str, from_rpc_to_intermediate_value, PluginEntrypointType, UiWidgetId};
use crate::plugins::config_reader::ConfigReader;
use crate::plugins::data_db_repository::DataDbRepository;
use crate::plugins::data_db_repository::{DataDbRepository, DbPluginPreference, DbPluginPreferenceUserData};
use crate::plugins::js::{PluginCode, PluginCommand, OnePluginCommandData, PluginPermissions, PluginRuntimeData, start_plugin_runtime, AllPluginCommandData};
use crate::plugins::loader::PluginLoader;
use crate::plugins::run_status::RunStatusHolder;
@ -69,12 +69,12 @@ impl ApplicationManager {
}
pub async fn plugins(&self) -> anyhow::Result<Vec<RpcPlugin>> {
let plugins = self.db_repository.list_plugins().await?;
let result = plugins
let result = self.db_repository
.list_plugins_and_entrypoints()
.await?
.into_iter()
.map(|plugin| {
let entrypoints = plugin.entrypoints
.map(|(plugin, entrypoints)| {
let entrypoints = entrypoints
.into_iter()
.map(|entrypoint| RpcEntrypoint {
enabled: entrypoint.enabled,
@ -84,7 +84,13 @@ impl ApplicationManager {
PluginEntrypointType::Command => RpcEntrypointType::Command,
PluginEntrypointType::View => RpcEntrypointType::View,
PluginEntrypointType::InlineView => RpcEntrypointType::InlineView
}.into()
}.into(),
preferences: entrypoint.preferences.into_iter()
.map(|(key, value)| (key, plugin_preference_to_grpc(value)))
.collect(),
preferences_user_data: entrypoint.preferences_user_data.into_iter()
.map(|(key, value)| (key, plugin_preference_user_data_to_grpc(value)))
.collect(),
})
.collect();
@ -93,6 +99,12 @@ impl ApplicationManager {
plugin_name: plugin.name,
enabled: plugin.enabled,
entrypoints,
preferences: plugin.preferences.into_iter()
.map(|(key, value)| (key, plugin_preference_to_grpc(value)))
.collect(),
preferences_user_data: plugin.preferences_user_data.into_iter()
.map(|(key, value)| (key, plugin_preference_user_data_to_grpc(value)))
.collect(),
}
})
.collect();
@ -270,12 +282,12 @@ impl ApplicationManager {
async fn reload_search_index(&self) -> anyhow::Result<()> {
tracing::info!("Reloading search index");
let search_items: Vec<_> = self.db_repository.list_plugins()
let search_items: Vec<_> = self.db_repository.list_plugins_and_entrypoints()
.await?
.into_iter()
.filter(|plugin| plugin.enabled)
.flat_map(|plugin| {
plugin.entrypoints
.filter(|(plugin, _)| plugin.enabled)
.flat_map(|(plugin, entrypoints)| {
entrypoints
.into_iter()
.filter(|entrypoint| entrypoint.enabled)
.map(|entrypoint| {
@ -310,3 +322,130 @@ impl ApplicationManager {
self.command_broadcaster.send(command).expect("all respective receivers were closed");
}
}
fn plugin_preference_to_grpc(value: DbPluginPreference) -> RpcPluginPreference {
match value {
DbPluginPreference::Number { default, description } => {
RpcPluginPreference {
r#type: RpcPluginPreferenceValueType::Number.into(),
default: default.map(|value| RpcUiPropertyValue { value: Some(rpc_ui_property_value::Value::Number(value)) }),
description,
..RpcPluginPreference::default()
}
}
DbPluginPreference::String { default, description } => {
RpcPluginPreference {
r#type: RpcPluginPreferenceValueType::String.into(),
default: default.map(|value| RpcUiPropertyValue { value: Some(rpc_ui_property_value::Value::String(value)) }),
description,
..RpcPluginPreference::default()
}
}
DbPluginPreference::Enum { default, description, enum_values } => {
RpcPluginPreference {
r#type: RpcPluginPreferenceValueType::Enum.into(),
default: default.map(|value| RpcUiPropertyValue { value: Some(rpc_ui_property_value::Value::String(value)) }),
description,
enum_values: enum_values.into_iter()
.map(|value| RpcEnumValue { label: value.label, value: value.value })
.collect(),
..RpcPluginPreference::default()
}
}
DbPluginPreference::Bool { default, description } => {
RpcPluginPreference {
r#type: RpcPluginPreferenceValueType::Bool.into(),
default: default.map(|value| RpcUiPropertyValue { value: Some(rpc_ui_property_value::Value::Bool(value)) }),
description,
..RpcPluginPreference::default()
}
}
DbPluginPreference::ListOfStrings { default, description } => {
RpcPluginPreference {
r#type: RpcPluginPreferenceValueType::ListOfStrings.into(),
default_list: default.map(|value| value.into_iter().map(|value| RpcUiPropertyValue { value: Some(rpc_ui_property_value::Value::String(value)) }).collect()).unwrap_or(vec![]),
description,
..RpcPluginPreference::default()
}
}
DbPluginPreference::ListOfNumbers { default, description } => {
RpcPluginPreference {
r#type: RpcPluginPreferenceValueType::ListOfNumbers.into(),
default_list: default.map(|value| value.into_iter().map(|value| RpcUiPropertyValue { value: Some(rpc_ui_property_value::Value::Number(value)) }).collect()).unwrap_or(vec![]),
description,
..RpcPluginPreference::default()
}
}
DbPluginPreference::ListOfEnums { default, enum_values, description } => {
RpcPluginPreference {
r#type: RpcPluginPreferenceValueType::ListOfEnums.into(),
default_list: default.map(|value| value.into_iter().map(|value| RpcUiPropertyValue { value: Some(rpc_ui_property_value::Value::String(value)) }).collect()).unwrap_or(vec![]),
description,
enum_values: enum_values.into_iter()
.map(|value| RpcEnumValue { label: value.label, value: value.value })
.collect(),
..RpcPluginPreference::default()
}
}
}
}
fn plugin_preference_user_data_to_grpc(value: DbPluginPreferenceUserData) -> RpcPluginPreferenceUserData {
match value {
DbPluginPreferenceUserData::Number { value } => {
RpcPluginPreferenceUserData {
r#type: RpcPluginPreferenceValueType::Number.into(),
value: value.map(|value| RpcUiPropertyValue { value: Some(rpc_ui_property_value::Value::Number(value)) }),
..RpcPluginPreferenceUserData::default()
}
}
DbPluginPreferenceUserData::String { value } => {
RpcPluginPreferenceUserData {
r#type: RpcPluginPreferenceValueType::String.into(),
value: value.map(|value| RpcUiPropertyValue { value: Some(rpc_ui_property_value::Value::String(value)) }),
..RpcPluginPreferenceUserData::default()
}
}
DbPluginPreferenceUserData::Enum { value } => {
RpcPluginPreferenceUserData {
r#type: RpcPluginPreferenceValueType::Enum.into(),
value: value.map(|value| RpcUiPropertyValue { value: Some(rpc_ui_property_value::Value::String(value)) }),
..RpcPluginPreferenceUserData::default()
}
}
DbPluginPreferenceUserData::Bool { value } => {
RpcPluginPreferenceUserData {
r#type: RpcPluginPreferenceValueType::Bool.into(),
value: value.map(|value| RpcUiPropertyValue { value: Some(rpc_ui_property_value::Value::Bool(value)) }),
..RpcPluginPreferenceUserData::default()
}
}
DbPluginPreferenceUserData::ListOfStrings { value } => {
let exists = value.is_some();
RpcPluginPreferenceUserData {
r#type: RpcPluginPreferenceValueType::ListOfStrings.into(),
value_list: value.map(|value| value.into_iter().map(|value| RpcUiPropertyValue { value: Some(rpc_ui_property_value::Value::String(value)) }).collect()).unwrap_or(vec![]),
value_list_exists: exists,
..RpcPluginPreferenceUserData::default()
}
}
DbPluginPreferenceUserData::ListOfNumbers { value } => {
let exists = value.is_some();
RpcPluginPreferenceUserData {
r#type: RpcPluginPreferenceValueType::ListOfNumbers.into(),
value_list: value.map(|value| value.into_iter().map(|value| RpcUiPropertyValue { value: Some(rpc_ui_property_value::Value::Number(value)) }).collect()).unwrap_or(vec![]),
value_list_exists: exists,
..RpcPluginPreferenceUserData::default()
}
}
DbPluginPreferenceUserData::ListOfEnums { value } => {
let exists = value.is_some();
RpcPluginPreferenceUserData {
r#type: RpcPluginPreferenceValueType::ListOfEnums.into(),
value_list: value.map(|value| value.into_iter().map(|value| RpcUiPropertyValue { value: Some(rpc_ui_property_value::Value::String(value)) }).collect()).unwrap_or(vec![]),
value_list_exists: exists,
..RpcPluginPreferenceUserData::default()
}
}
}
}

View file

@ -14,7 +14,7 @@ service RpcBackend {
rpc SendViewEvent (RpcSendViewEventRequest) returns (RpcSendViewEventResponse);
// settings
rpc plugins (RpcPluginsRequest) returns (RpcPluginsResponse);
rpc Plugins (RpcPluginsRequest) returns (RpcPluginsResponse);
rpc SetPluginState(RpcSetPluginStateRequest) returns (RpcSetPluginStateResponse);
@ -114,6 +114,8 @@ message RpcPlugin {
string plugin_name = 2;
bool enabled = 3;
repeated RpcEntrypoint entrypoints = 4;
map<string, RpcPluginPreference> preferences = 5;
map<string, RpcPluginPreferenceUserData> preferences_user_data = 6;
}
message RpcEntrypoint {
@ -121,6 +123,8 @@ message RpcEntrypoint {
string entrypoint_name = 2;
bool enabled = 3;
RpcEntrypointType entrypoint_type = 4;
map<string, RpcPluginPreference> preferences = 5;
map<string, RpcPluginPreferenceUserData> preferences_user_data = 6;
}
@ -150,3 +154,41 @@ message RpcDownloadStatusValue {
string message = 2;
}
// protobuf is shit, hopefully somebody soon comes up with normal format using wasm wit or something
message RpcPluginPreference {
RpcPluginPreferenceValueType type = 1;
RpcUiPropertyValue default = 2;
repeated RpcUiPropertyValue default_list = 3;
bool default_list_exists = 4;
string description = 5;
repeated RpcEnumValue enum_values = 6;
}
message RpcEnumValue {
string label = 1;
string value = 2;
}
message RpcKeyValue {
string key = 1;
string value = 2;
}
message RpcPluginPreferenceUserData {
RpcPluginPreferenceValueType type = 1;
RpcUiPropertyValue value = 2;
repeated RpcUiPropertyValue value_list = 3;
bool value_list_exists = 4;
}
enum RpcPluginPreferenceValueType {
Number = 0;
String = 1;
Enum = 2;
Bool = 3;
ListOfStrings = 4;
ListOfNumbers = 5;
ListOfEnums = 6;
}