fix(web): link plugins to desktop app

Keep browser entry points visible while explaining that native
plugins require a desktop install.

Refs #567
This commit is contained in:
Hakan Seven committed 2026-07-29 16:28:20 +03:00
1 parent 2424eeb74d
commit fcc6e1f8e1
9 files changed
+92 -48

No files matched your search

+2 -2
View File
@@ -236,6 +236,8 @@ pub fn start_allowed(cmd: &str) -> bool {
| "REPORT"
| "CHANGELOG"
| "ABOUT"
| "PLUGINS"
| "PLUGINMANAGER"
| "DONATE"
| "WEBVERSION"
| "HELP"
@@ -245,8 +247,6 @@ pub fn start_allowed(cmd: &str) -> bool {
| "CUILOAD"
| "CUIIMPORT"
)
|| (!cfg!(target_arch = "wasm32")
&& matches!(cmd, "PLUGINS" | "PLUGINMANAGER"))
}
// ── Autocomplete registry — one-shot commands ──────────────────────────────
-7
View File
@@ -212,17 +212,10 @@ impl OpenCADStudio {
return Some(Task::done(Message::AboutOpen));
}
#[cfg(not(target_arch = "wasm32"))]
"PLUGINS" | "PLUGINMANAGER" => {
return Some(Task::done(Message::PluginManagerOpen));
}
#[cfg(target_arch = "wasm32")]
"PLUGINS" | "PLUGINMANAGER" => {
self.command_line
.push_info("External plugins are available in the desktop app.");
}
"CHANGELOG" => {
crate::sys::open_url("https://github.com/HakanSeven12/OpenCADStudio/releases");
self.command_line.push_info("Opening release notes...");
+1 -1
View File
@@ -521,6 +521,7 @@ pub(super) struct OpenCADStudio {
external_plugins: Vec<crate::plugin::external::ExternalPlugin>,
/// Ids of external packages actually loaded this session (a subset of
/// `external_plugins` — compatible, with a library, dlopen'd at startup).
#[cfg_attr(target_arch = "wasm32", allow(dead_code))]
loaded_plugin_ids: rustc_hash::FxHashSet<String>,
/// Curated plugin registry fetched from the OpenCADStudio repo.
plugin_registry: Vec<crate::plugin::external::RegistryEntry>,
@@ -1313,7 +1314,6 @@ impl ClipboardDeps {
pub enum ModalKind {
About,
Shortcuts,
#[cfg_attr(target_arch = "wasm32", allow(dead_code))]
PluginManager,
UpdateNotice,
Layers,
+1 -2
View File
@@ -4058,8 +4058,7 @@ impl OpenCADStudio {
Message::PluginManagerOpen => {
#[cfg(target_arch = "wasm32")]
{
self.command_line
.push_info("External plugins are available in the desktop app.");
self.active_modal = Some(super::ModalKind::PluginManager);
return Task::none();
}
#[cfg(not(target_arch = "wasm32"))]
+3 -3
View File
@@ -2300,11 +2300,11 @@ pub(super) fn start_page_view<'a>(
.into(),
outline_btn("Options", Message::OptionsOpen).into(),
];
// External plugins are native dynamic libraries and the web build is
// already in the browser, so both actions are desktop-only.
secondary_items.push(outline_btn("Plugins", Message::PluginManagerOpen).into());
// The web build is already in the browser, so only the desktop offers a
// link to the web version.
#[cfg(not(target_arch = "wasm32"))]
{
secondary_items.push(outline_btn("Plugins", Message::PluginManagerOpen).into());
// Filled with the active theme's primary colour.
secondary_items.push(
button(text("OCS Web").size(14))
+39 -25
View File
@@ -71,31 +71,45 @@ impl OpenCADStudio {
520,
500,
),
super::super::ModalKind::PluginManager => sized(
crate::ui::window::plugin_manager::view_window(
&self.disabled_plugins,
&self.external_plugins,
&self.loaded_plugin_ids,
crate::ui::window::plugin_manager::MarketView {
registry: &self.plugin_registry,
registry_loading: self.plugin_registry_loading,
registry_error: self.plugin_registry_error.as_deref(),
registry_error_details_open: self.plugin_registry_error_details_open,
input: &self.plugin_repo_input,
search: &self.plugin_search_input,
repos: &self.plugin_repos,
release_tags: &self.repo_release_tags,
selected_tag: &self.repo_selected_tag,
selected_repo: self.selected_plugin_repo.as_deref(),
readmes: &self.plugin_readmes,
readme_loading: &self.plugin_readme_loading,
status: &self.marketplace_status,
},
&self.active_theme,
),
940,
600,
),
super::super::ModalKind::PluginManager => {
#[cfg(not(target_arch = "wasm32"))]
{
sized(
crate::ui::window::plugin_manager::view_window(
&self.disabled_plugins,
&self.external_plugins,
&self.loaded_plugin_ids,
crate::ui::window::plugin_manager::MarketView {
registry: &self.plugin_registry,
registry_loading: self.plugin_registry_loading,
registry_error: self.plugin_registry_error.as_deref(),
registry_error_details_open: self
.plugin_registry_error_details_open,
input: &self.plugin_repo_input,
search: &self.plugin_search_input,
repos: &self.plugin_repos,
release_tags: &self.repo_release_tags,
selected_tag: &self.repo_selected_tag,
selected_repo: self.selected_plugin_repo.as_deref(),
readmes: &self.plugin_readmes,
readme_loading: &self.plugin_readme_loading,
status: &self.marketplace_status,
},
&self.active_theme,
),
940,
600,
)
}
#[cfg(target_arch = "wasm32")]
{
sized(
crate::ui::window::plugin_manager::view_web_notice(),
520,
260,
)
}
}
super::super::ModalKind::UpdateNotice => {
let latest = self.update_notice_version.as_deref().unwrap_or("?");
let body = self.update_notice_body.as_deref().unwrap_or("");
+39 -3
View File
@@ -4,6 +4,8 @@
//! launches). Dynamic loading still comes with the phase-2 loader; see
//! `docs/plugin-architecture.md`.
#![cfg_attr(target_arch = "wasm32", allow(dead_code))]
use crate::app::Message;
use crate::plugin::external::{ExternalPlugin, RegistryEntry};
use iced::widget::{
@@ -33,9 +35,13 @@ pub struct MarketView<'a> {
pub status: &'a str,
}
// External plugins are native dynamic libraries, so the browser build must not
// advertise a manager it cannot use.
#[cfg(not(target_arch = "wasm32"))]
/// Latest desktop builds, used by the browser-only plugin notice.
#[cfg(target_arch = "wasm32")]
pub const DESKTOP_DOWNLOAD_URL: &str =
"https://github.com/HakanSeven12/OpenCADStudio/releases/latest";
// Register the command names for autocomplete. On the web they open a desktop
// download notice instead of the native marketplace.
inventory::submit!(crate::command::CommandRegistration {
names: &["PLUGINS", "PLUGINMANAGER"]
});
@@ -844,6 +850,36 @@ pub fn view_window<'a>(
.into()
}
/// Browser replacement for the native Plugin Manager.
#[cfg(target_arch = "wasm32")]
pub fn view_web_notice<'a>() -> Element<'a, Message> {
let download = button(text("Download desktop app").size(13))
.on_press(Message::OpenUrl(DESKTOP_DOWNLOAD_URL.to_string()))
.padding([8, 16])
.style(button::primary);
container(
column![
text("Plugins require the desktop app").size(20),
text(
"Open CAD Studio plugins are native packages and cannot run inside a browser. \
Install the desktop app to browse, install, and use plugins.",
)
.size(13)
.style(muted_style),
Space::new().height(8),
download,
]
.spacing(8)
.padding(24)
.width(Fill),
)
.center(Fill)
.width(Fill)
.height(Fill)
.into()
}
#[cfg(test)]
mod tests {
use super::{newest_update, registry_error_message, repository_display_name};