Skip to content

Commit e029ddf

Browse files
SteveLauCayangwebRainyNight9
authored
fix(view extension): broken search bar UI when opening extensions via hotkey (#938)
* fix: open view extension via hotkey * refactor: update * refactor: update * chore: check error * chore: ci update * release notes --------- Co-authored-by: ayang <473033518@qq.com> Co-authored-by: rain9 <15911122312@163.com>
1 parent 731cfc5 commit e029ddf

11 files changed

Lines changed: 74 additions & 39 deletions

File tree

.github/workflows/frontend-ci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ jobs:
1919
steps:
2020
- name: Checkout code
2121
uses: actions/checkout@v4
22+
with:
23+
ref: ${{ github.head_ref }}
24+
fetch-depth: 0
2225

2326
- name: Setup Node.js
2427
uses: actions/setup-node@v4

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ fix: resolve pinned window shortcut not working #917
3232
fix: WM ext does not work when operating focused win from another display #919
3333
fix(Window Management): Next/Previous Desktop do not work #926
3434
fix: fix page rapidly flickering issue #935
35+
fix(view extension): broken search bar UI when opening extensions via hotkey #938
3536

3637
### ✈️ Improvements
3738

src-tauri/src/common/document.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
use crate::extension::built_in::window_management::actions::Action;
33
use crate::extension::{ExtensionPermission, ExtensionSettings, ViewExtensionUISettings};
44
use serde::{Deserialize, Serialize};
5+
use serde_json::Value as Json;
56
use std::collections::HashMap;
67
use tauri::{AppHandle, Emitter};
78

@@ -133,7 +134,7 @@ impl OnOpened {
133134
pub(crate) async fn open(
134135
tauri_app_handle: AppHandle,
135136
on_opened: OnOpened,
136-
extra_args: Option<HashMap<String, String>>,
137+
extra_args: Option<HashMap<String, Json>>,
137138
) -> Result<(), String> {
138139
use crate::util::open as homemade_tauri_shell_open;
139140
use std::process::Command;
@@ -244,10 +245,17 @@ pub(crate) async fn open(
244245
use serde_json::Value as Json;
245246
use serde_json::to_value;
246247

247-
let page_and_permission: [Json; 3] = [
248+
let mut extra_args =
249+
extra_args.expect("extra_args is needed to open() a view extension");
250+
let document = extra_args.remove("document").expect(
251+
"extra argument [document] should be provided to open a view extension",
252+
);
253+
254+
let page_and_permission: [Json; 4] = [
248255
Json::String(page),
249256
to_value(permission).unwrap(),
250257
to_value(ui).unwrap(),
258+
document,
251259
];
252260
tauri_app_handle
253261
.emit("open_view_extension", page_and_permission)

src-tauri/src/extension/mod.rs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ impl QuicklinkLink {
430430
/// if any.
431431
pub(crate) fn concatenate_url(
432432
&self,
433-
user_supplied_args: &Option<HashMap<String, String>>,
433+
user_supplied_args: &Option<HashMap<String, Json>>,
434434
) -> String {
435435
let mut out = String::new();
436436
for component in self.components.iter() {
@@ -442,20 +442,23 @@ impl QuicklinkLink {
442442
argument_name,
443443
default,
444444
} => {
445-
let opt_argument_value = {
445+
let opt_argument_value: Option<&str> = {
446446
let user_supplied_arg = user_supplied_args
447447
.as_ref()
448448
.and_then(|map| map.get(argument_name.as_str()));
449449

450450
if user_supplied_arg.is_some() {
451-
user_supplied_arg
451+
user_supplied_arg.map(|json| {
452+
json.as_str()
453+
.expect("quicklink should provide string arguments")
454+
})
452455
} else {
453-
default.as_ref()
456+
default.as_deref()
454457
}
455458
};
456459

457460
let argument_value_str = match opt_argument_value {
458-
Some(str) => str.as_str(),
461+
Some(str) => str,
459462
// None => an empty string
460463
None => "",
461464
};
@@ -1763,7 +1766,7 @@ mod tests {
17631766
],
17641767
};
17651768
let mut user_args = HashMap::new();
1766-
user_args.insert("other_param".to_string(), "value".to_string());
1769+
user_args.insert("other_param".to_string(), Json::String("value".to_string()));
17671770
let result = link.concatenate_url(&Some(user_args));
17681771
assert_eq!(result, "https://www.google.com/search?q=");
17691772
}
@@ -1800,7 +1803,7 @@ mod tests {
18001803
],
18011804
};
18021805
let mut user_args = HashMap::new();
1803-
user_args.insert("other_param".to_string(), "value".to_string());
1806+
user_args.insert("other_param".to_string(), Json::String("value".to_string()));
18041807
let result = link.concatenate_url(&Some(user_args));
18051808
assert_eq!(result, "https://www.google.com/search?q=rust");
18061809
}
@@ -1823,7 +1826,7 @@ mod tests {
18231826
],
18241827
};
18251828
let mut user_args = HashMap::new();
1826-
user_args.insert("query".to_string(), "python".to_string());
1829+
user_args.insert("query".to_string(), Json::String("python".to_string()));
18271830
let result = link.concatenate_url(&Some(user_args));
18281831
assert_eq!(result, "https://www.google.com/search?q=python");
18291832
}

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

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use async_trait::async_trait;
2323
use borrowme::ToOwned;
2424
use check::general_check;
2525
use function_name::named;
26+
use std::collections::HashMap;
2627
use std::io::ErrorKind;
2728
use std::path::Path;
2829
use std::path::PathBuf;
@@ -524,6 +525,24 @@ impl ThirdPartyExtensionsSearchSource {
524525
let on_opened = extension.on_opened().unwrap_or_else(|| panic!(
525526
"setting hotkey for an extension that cannot be opened, extension ID [{:?}], extension type [{:?}]", bundle_id, extension.r#type,
526527
));
528+
let url = on_opened.url();
529+
let extension_type_string = extension.r#type.to_string();
530+
let document = Document {
531+
id: extension.id.clone(),
532+
title: Some(extension.name.clone()),
533+
icon: Some(extension.icon.clone()),
534+
on_opened: Some(on_opened.clone()),
535+
url: Some(url),
536+
category: Some(extension_type_string.clone()),
537+
source: Some(DataSourceReference {
538+
id: Some(extension_type_string.clone()),
539+
name: Some(extension_type_string.clone()),
540+
icon: None,
541+
r#type: Some(extension_type_string),
542+
}),
543+
544+
..Default::default()
545+
};
527546

528547
let bundle_id_owned = bundle_id.to_owned();
529548
tauri_app_handle
@@ -533,9 +552,16 @@ impl ThirdPartyExtensionsSearchSource {
533552
let bundle_id_clone = bundle_id_owned.clone();
534553
let app_handle_clone = tauri_app_handle.clone();
535554

555+
let document_clone = document.clone();
536556
if event.state() == ShortcutState::Pressed {
537557
async_runtime::spawn(async move {
538-
let result = open(app_handle_clone, on_opened_clone, None).await;
558+
let mut args = HashMap::new();
559+
args.insert(
560+
String::from("document"),
561+
serde_json::to_value(&document_clone).unwrap(),
562+
);
563+
564+
let result = open(app_handle_clone, on_opened_clone, Some(args)).await;
539565
if let Err(msg) = result {
540566
log::warn!(
541567
"failed to open extension [{:?}], error [{}]",

src/components/Search/AssistantManager.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -185,18 +185,17 @@ export function useAssistantManager({
185185
const onOpened = selectedSearchContent?.on_opened;
186186

187187
if (onOpened?.Extension?.ty?.View) {
188-
const { setViewExtensionOpened, setViewExtensionData } =
189-
useSearchStore.getState();
188+
const { setViewExtensionOpened } = useSearchStore.getState();
190189
const viewData = onOpened.Extension.ty.View;
191190
const extensionPermission = onOpened.Extension.permission;
192191

193192
clearSearchValue();
194-
setViewExtensionOpened([
193+
return setViewExtensionOpened([
195194
viewData.page,
196195
extensionPermission,
197196
viewData.ui,
197+
selectedSearchContent as any,
198198
]);
199-
return setViewExtensionData(selectedSearchContent as any);
200199
}
201200
}
202201

src/components/Search/SearchIcons.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@ export default function SearchIcons({
7575
visibleExtensionDetail,
7676
selectedExtension,
7777
viewExtensionOpened,
78-
viewExtensionData,
7978
} = useSearchStore();
8079

8180
if (isChatMode) {
@@ -106,8 +105,8 @@ export default function SearchIcons({
106105
return <MultilevelWrapper title={name} icon={icon} />;
107106
}
108107

109-
if (viewExtensionOpened && viewExtensionData) {
110-
const { title, icon } = viewExtensionData;
108+
if (viewExtensionOpened) {
109+
const { title, icon } = viewExtensionOpened[3];
111110

112111
const iconPath = icon ? platformAdapter.convertFileSrc(icon) : void 0;
113112

src/components/Search/ViewExtension.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ import {
77
FileSystemAccess,
88
} from "../Settings/Extensions";
99
import platformAdapter from "@/utils/platformAdapter";
10+
import { useShortcutsStore } from "@/stores/shortcutsStore";
1011

1112
const ViewExtension: React.FC = () => {
1213
const { viewExtensionOpened } = useSearchStore();
1314
const [page, setPage] = useState<string>("");
1415
// Complete list of the backend APIs, grouped by their category.
1516
const [apis, setApis] = useState<Map<string, string[]> | null>(null);
17+
const { setModifierKeyPressed } = useShortcutsStore();
1618

1719
if (viewExtensionOpened == null) {
1820
// When this view gets loaded, this state should not be NULL.
@@ -29,19 +31,20 @@ const ViewExtension: React.FC = () => {
2931
const page = viewExtensionOpened[0];
3032

3133
// Only convert to file source if it's a local file path, not a URL
32-
if (page.startsWith('http://') || page.startsWith('https://')) {
34+
if (page.startsWith("http://") || page.startsWith("https://")) {
3335
setPage(page);
3436
} else {
3537
setPage(platformAdapter.convertFileSrc(page));
3638
}
37-
3839
};
3940

4041
setupFileUrl();
4142
}, [viewExtensionOpened]);
4243

4344
// invoke `apis()` and set the state
4445
useEffect(() => {
46+
setModifierKeyPressed(false);
47+
4548
const fetchApis = async () => {
4649
try {
4750
const availableApis = (await platformAdapter.invokeBackend(

src/stores/extensionsStore.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { ExtensionId } from "@/components/Settings/Extensions";
21
import { create } from "zustand";
32
import { persist, subscribeWithSelector } from "zustand/middleware";
43

4+
import { ExtensionId } from "@/components/Settings/Extensions";
5+
56
export type IExtensionsStore = {
67
quickAiAccessServer?: any;
78
setQuickAiAccessServer: (quickAiAccessServer?: any) => void;

src/stores/searchStore.ts

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@ import { SearchDocument } from "@/types/search";
77
import { create } from "zustand";
88
import { persist } from "zustand/middleware";
99

10-
export type ViewExtensionOpened =
11-
| [string, ExtensionPermission | null, ViewExtensionUISettings | null]
12-
| null;
10+
export type ViewExtensionOpened = [
11+
string,
12+
ExtensionPermission | null,
13+
ViewExtensionUISettings | null,
14+
SearchDocument
15+
];
1316

1417
export type ISearchStore = {
1518
sourceData: any;
@@ -58,11 +61,8 @@ export type ISearchStore = {
5861
// The first array element is the path to the page that we should load
5962
// The second element is the permission that this extension requires.
6063
// The third argument is the UI Settings
61-
viewExtensionOpened: ViewExtensionOpened;
62-
setViewExtensionOpened: (showViewExtension: ViewExtensionOpened) => void;
63-
64-
viewExtensionData?: SearchDocument;
65-
setViewExtensionData: (viewExtensionData?: SearchDocument) => void;
64+
viewExtensionOpened?: ViewExtensionOpened;
65+
setViewExtensionOpened: (showViewExtension?: ViewExtensionOpened) => void;
6666
};
6767

6868
export const useSearchStore = create<ISearchStore>()(
@@ -128,13 +128,9 @@ export const useSearchStore = create<ISearchStore>()(
128128
setVisibleExtensionDetail: (visibleExtensionDetail) => {
129129
return set({ visibleExtensionDetail });
130130
},
131-
viewExtensionOpened: null,
132131
setViewExtensionOpened: (viewExtensionOpened) => {
133132
return set({ viewExtensionOpened });
134133
},
135-
setViewExtensionData(viewExtensionData) {
136-
return set({ viewExtensionData });
137-
},
138134
}),
139135
{
140136
name: "search-store",

0 commit comments

Comments
 (0)