Skip to content

Commit 859def2

Browse files
ayangwebSteveLauC
andauthored
feat: standardize multi-level menu label structure (#925)
* feat: standardize multi-level menu label structure * refactor: update * refactor: improve tab behavior * refactor: update * refactor: improve backspace behavior * refactor: optimizes tab behavior * refactor: optimizes backspace behavior * refactor: disable calculator subpage navigation * refactor: iframe auto focus * ViewExtension UI settings * refactor: update * fix Rust code build * refactor: update * refactor: update * refactor: update * fix tests * support http pages directly * support http pages directly * docs: update changelog * field ui can only be set by View extensions * changelog: View Extension page field now accepts HTTP(s) links --------- Co-authored-by: Steve Lau <stevelauc@outlook.com>
1 parent 6145306 commit 859def2

23 files changed

Lines changed: 536 additions & 289 deletions

File tree

docs/content.en/docs/release-notes/_index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ feat: support switching groups via keyboard shortcuts #911
1717
feat: support opening logs from about page #915
1818
feat: support moving cursor with home and end keys #918
1919
feat: support pageup/pagedown to navigate search results #920
20+
feat: standardize multi-level menu label structure #925
21+
feat(View Extension): page field now accepts HTTP(s) links #925
2022
feat: return sub-exts when extension type exts themselves are matched #928
2123

2224
### 🐛 Bug fix

src-tauri/src/common/document.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#[cfg(target_os = "macos")]
22
use crate::extension::built_in::window_management::actions::Action;
3-
use crate::extension::{ExtensionPermission, ExtensionSettings};
3+
use crate::extension::{ExtensionPermission, ExtensionSettings, ViewExtensionUISettings};
44
use serde::{Deserialize, Serialize};
55
use std::collections::HashMap;
66
use tauri::{AppHandle, Emitter};
@@ -89,6 +89,7 @@ pub(crate) enum ExtensionOnOpenedType {
8989
///
9090
/// It should be an absolute path or Tauri cannot open it.
9191
page: String,
92+
ui: Option<ViewExtensionUISettings>,
9293
},
9394
}
9495

@@ -118,7 +119,7 @@ impl OnOpened {
118119
// The URL of a quicklink is nearly useless without such dynamic user
119120
// inputs, so until we have dynamic URL support, we just use "N/A".
120121
ExtensionOnOpenedType::Quicklink { .. } => String::from("N/A"),
121-
ExtensionOnOpenedType::View { page: _ } => {
122+
ExtensionOnOpenedType::View { page: _, ui: _ } => {
122123
// We currently don't have URL for this kind of extension.
123124
String::from("N/A")
124125
}
@@ -231,7 +232,7 @@ pub(crate) async fn open(
231232
}
232233
}
233234
}
234-
ExtensionOnOpenedType::View { page } => {
235+
ExtensionOnOpenedType::View { page, ui } => {
235236
/*
236237
* Emit an event to let the frontend code open this extension.
237238
*
@@ -243,8 +244,11 @@ pub(crate) async fn open(
243244
use serde_json::Value as Json;
244245
use serde_json::to_value;
245246

246-
let page_and_permission: [Json; 2] =
247-
[Json::String(page), to_value(permission).unwrap()];
247+
let page_and_permission: [Json; 3] = [
248+
Json::String(page),
249+
to_value(permission).unwrap(),
250+
to_value(ui).unwrap(),
251+
];
248252
tauri_app_handle
249253
.emit("open_view_extension", page_and_permission)
250254
.unwrap();

src-tauri/src/extension/built_in/application/with_feature.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1242,6 +1242,7 @@ pub async fn get_app_list(tauri_app_handle: AppHandle) -> Result<Vec<Extension>,
12421242
enabled,
12431243
settings: None,
12441244
page: None,
1245+
ui: None,
12451246
permission: None,
12461247
screenshots: None,
12471248
url: None,

src-tauri/src/extension/mod.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ pub struct Extension {
112112
/// and render. Otherwise, `None`.
113113
page: Option<String>,
114114

115+
ui: Option<ViewExtensionUISettings>,
116+
115117
/// Permission that this extension requires.
116118
permission: Option<ExtensionPermission>,
117119

@@ -126,6 +128,17 @@ pub struct Extension {
126128
version: Option<Json>,
127129
}
128130

131+
/// Settings that control the built-in UI Components
132+
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
133+
pub(crate) struct ViewExtensionUISettings {
134+
/// Show the search bar
135+
search_bar: bool,
136+
/// Show the filter bar
137+
filter_bar: bool,
138+
/// Show the footer
139+
footer: bool,
140+
}
141+
129142
/// Bundle ID uniquely identifies an extension.
130143
#[derive(Debug, Deserialize, Serialize, PartialEq, Clone)]
131144
pub(crate) struct ExtensionBundleId {
@@ -265,8 +278,9 @@ impl Extension {
265278
let page = self.page.as_ref().unwrap_or_else(|| {
266279
panic!("View extension [{}]'s [page] field is not set, something wrong with your extension validity check", self.id);
267280
}).clone();
281+
let ui = self.ui.clone();
268282

269-
let extension_on_opened_type = ExtensionOnOpenedType::View { page };
283+
let extension_on_opened_type = ExtensionOnOpenedType::View { page, ui };
270284
let extension_on_opened = ExtensionOnOpened {
271285
ty: extension_on_opened_type,
272286
settings,
@@ -963,6 +977,14 @@ pub(crate) fn canonicalize_relative_page_path(
963977
.page
964978
.as_ref()
965979
.expect("this should be invoked on a View extension");
980+
981+
// Skip HTTP links
982+
if let Ok(url) = url::Url::parse(page)
983+
&& ["http", "https"].contains(&url.scheme())
984+
{
985+
return Ok(());
986+
}
987+
966988
let page_path = Path::new(page);
967989

968990
if page_path.is_relative() {

src-tauri/src/extension/third_party/check.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,14 @@ fn check_main_extension_or_sub_extension(
231231
));
232232
}
233233

234+
// If field `ui` is Some, then it should be a View
235+
if extension.ui.is_some() && extension.r#type != ExtensionType::View {
236+
return Err(format!(
237+
"invalid {}, field [ui] is set for a non-View extension",
238+
identifier
239+
));
240+
}
241+
234242
Ok(())
235243
}
236244

@@ -267,6 +275,7 @@ mod tests {
267275
hotkey: None,
268276
enabled: true,
269277
page,
278+
ui: None,
270279
permission: None,
271280
settings: None,
272281
screenshots: None,

src-tauri/src/extension/third_party/install/local_extension.rs

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -223,49 +223,58 @@ pub(crate) async fn install_local_extension(
223223

224224
/*
225225
* Call convert_page() to update the page files. This has to be done after
226-
* writing the extension files
226+
* writing the extension files because we will edit them.
227+
*
228+
* HTTP links will be skipped.
227229
*/
228-
let absolute_page_paths: Vec<PathBuf> = {
229-
fn canonicalize_page_path(page_path: &Path, extension_root: &Path) -> PathBuf {
230-
if page_path.is_relative() {
231-
// It is relative to the extension root directory
232-
extension_root.join(page_path)
233-
} else {
234-
page_path.into()
235-
}
236-
}
237-
230+
let pages: Vec<&str> = {
238231
if extension.r#type == ExtensionType::View {
239232
let page = extension
240233
.page
241234
.as_ref()
242235
.expect("View extension should set its page field");
243-
let path = canonicalize_page_path(Path::new(page.as_str()), &dest_dir);
244236

245-
vec![path]
237+
vec![page.as_str()]
246238
} else if extension.r#type.contains_sub_items()
247239
&& let Some(ref views) = extension.views
248240
{
249-
let mut paths = Vec::with_capacity(views.len());
241+
let mut pages = Vec::with_capacity(views.len());
250242

251243
for view in views.iter() {
252244
let page = view
253245
.page
254246
.as_ref()
255247
.expect("View extension should set its page field");
256-
let path = canonicalize_page_path(Path::new(page.as_str()), &dest_dir);
257248

258-
paths.push(path);
249+
pages.push(page.as_str());
259250
}
260251

261-
paths
252+
pages
262253
} else {
263254
// No pages in this extension
264255
Vec::new()
265256
}
266257
};
267-
for page_path in absolute_page_paths {
268-
convert_page(&page_path).await?;
258+
fn canonicalize_page_path(page_path: &Path, extension_root: &Path) -> PathBuf {
259+
if page_path.is_relative() {
260+
// It is relative to the extension root directory
261+
extension_root.join(page_path)
262+
} else {
263+
page_path.into()
264+
}
265+
}
266+
for page in pages {
267+
/*
268+
* Skip HTTP links
269+
*/
270+
if let Ok(url) = url::Url::parse(page)
271+
&& ["http", "https"].contains(&url.scheme())
272+
{
273+
continue;
274+
}
275+
276+
let path = canonicalize_page_path(Path::new(page), &dest_dir);
277+
convert_page(&path).await?;
269278
}
270279

271280
// Canonicalize relative icon and page paths

src-tauri/src/extension/third_party/install/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ mod tests {
259259
enabled: true,
260260
settings: None,
261261
page: None,
262+
ui: None,
262263
permission: None,
263264
screenshots: None,
264265
url: None,

src-tauri/src/extension/third_party/install/store.rs

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -403,47 +403,54 @@ pub(crate) async fn install_extension_from_store(
403403
* Call convert_page() to update the page files. This has to be done after
404404
* writing the extension files
405405
*/
406-
let absolute_page_paths: Vec<PathBuf> = {
407-
fn canonicalize_page_path(page_path: &Path, extension_root: &Path) -> PathBuf {
408-
if page_path.is_relative() {
409-
// It is relative to the extension root directory
410-
extension_root.join(page_path)
411-
} else {
412-
page_path.into()
413-
}
414-
}
415-
406+
let pages: Vec<&str> = {
416407
if extension.r#type == ExtensionType::View {
417408
let page = extension
418409
.page
419410
.as_ref()
420411
.expect("View extension should set its page field");
421-
let path = canonicalize_page_path(Path::new(page.as_str()), &extension_directory);
422412

423-
vec![path]
413+
vec![path.as_str()]
424414
} else if extension.r#type.contains_sub_items()
425415
&& let Some(ref views) = extension.views
426416
{
427-
let mut paths = Vec::with_capacity(views.len());
417+
let mut pages = Vec::with_capacity(views.len());
428418

429419
for view in views.iter() {
430420
let page = view
431421
.page
432422
.as_ref()
433423
.expect("View extension should set its page field");
434-
let path = canonicalize_page_path(Path::new(page.as_str()), &extension_directory);
435424

436-
paths.push(path);
425+
pages.push(page.as_str());
437426
}
438427

439-
paths
428+
pages
440429
} else {
441430
// No pages in this extension
442431
Vec::new()
443432
}
444433
};
445-
for page_path in absolute_page_paths {
446-
convert_page(&page_path).await?;
434+
fn canonicalize_page_path(page_path: &Path, extension_root: &Path) -> PathBuf {
435+
if page_path.is_relative() {
436+
// It is relative to the extension root directory
437+
extension_root.join(page_path)
438+
} else {
439+
page_path.into()
440+
}
441+
}
442+
for page in pages {
443+
/*
444+
* Skip HTTP links
445+
*/
446+
if let Ok(url) = url::Url::parse(page)
447+
&& ["http", "https"].contains(&url.scheme())
448+
{
449+
continue;
450+
}
451+
452+
let path = canonicalize_page_path(Path::new(page), &extension_directory);
453+
convert_page(&path).await?;
447454
}
448455

449456
// Canonicalize relative icon and page paths

src/components/Common/Icons/CommonIcon.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ function CommonIcon({
4444
// Handle regular icon types
4545
const renderIconByType = (renderType: string) => {
4646
if (isNil(isAbsolute)) return null;
47-
47+
4848
switch (renderType) {
4949
case "special_icon": {
5050
if (item.id === "Calculator") {

src/components/Common/UI/SettingsFooter.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,4 +95,4 @@ const Footer = () => {
9595
);
9696
};
9797

98-
export default Footer;
98+
export default Footer;

0 commit comments

Comments
 (0)