mirror of
https://github.com/zen-browser/desktop.git
synced 2026-05-20 20:04:19 +00:00
no-bug: Add workspaces search (gh-12745)
Co-authored-by: mr. m <91018726+mr-cheffy@users.noreply.github.com> Co-authored-by: jababda <jababda@hotmail.com>
This commit is contained in:
@@ -79,6 +79,7 @@ zen-icons-picker-svg =
|
||||
.label = Icons
|
||||
|
||||
urlbar-search-mode-zen_actions = Actions
|
||||
urlbar-search-mode-workspaces = { zen-panel-ui-workspaces-text }
|
||||
zen-site-data-settings = Settings
|
||||
|
||||
zen-generic-manage = Manage
|
||||
|
||||
@@ -39,3 +39,6 @@
|
||||
|
||||
- name: zen.urlbar.suggestions.quick-actions
|
||||
value: true
|
||||
|
||||
- name: browser.urlbar.shortcuts.workspaces
|
||||
value: true
|
||||
@@ -1,12 +1,21 @@
|
||||
diff --git a/browser/components/urlbar/UrlbarPrefs.sys.mjs b/browser/components/urlbar/UrlbarPrefs.sys.mjs
|
||||
index 2d21248256c6c2bfb8dac958133c10e3251ef564..6645211ef09518b41cb737e3186fbd0162ecf700 100644
|
||||
index 2d21248256c6c2bfb8dac958133c10e3251ef564..f788bd10ec2c08e4b27b77cd3bb0489fb04e8b7a 100644
|
||||
--- a/browser/components/urlbar/UrlbarPrefs.sys.mjs
|
||||
+++ b/browser/components/urlbar/UrlbarPrefs.sys.mjs
|
||||
@@ -799,6 +799,7 @@ function makeDefaultResultGroups({ showSearchSuggestionsFirst }) {
|
||||
@@ -462,6 +462,7 @@ const PREF_URLBAR_DEFAULTS = /** @type {PreferenceDefinition[]} */ ([
|
||||
["shortcuts.tabs", true],
|
||||
["shortcuts.history", true],
|
||||
["shortcuts.actions", true],
|
||||
+ ["shortcuts.workspaces", true],
|
||||
|
||||
// Boolean to determine if the providers defined in `exposureResults`
|
||||
// should be displayed in search results. This can be set by a
|
||||
@@ -799,6 +800,8 @@ function makeDefaultResultGroups({ showSearchSuggestionsFirst }) {
|
||||
*/
|
||||
let rootGroup = {
|
||||
children: [
|
||||
+ { children: [{ group: lazy.UrlbarUtils.RESULT_GROUP.ZEN_ACTION }] },
|
||||
+ { children: [{ group: lazy.UrlbarUtils.RESULT_GROUP.ZEN_WORKSPACE }] },
|
||||
// heuristic
|
||||
{
|
||||
maxResultCount: 1,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
diff --git a/browser/components/urlbar/UrlbarProvidersManager.sys.mjs b/browser/components/urlbar/UrlbarProvidersManager.sys.mjs
|
||||
index 08455d8d5da233639ccebc0e77c0810fb4f674c3..78d0e875978b568b79646489c28b125a44ea79fa 100644
|
||||
index 08455d8d5da233639ccebc0e77c0810fb4f674c3..da8092b561c3dd8864e57f5a52a1a643db29ace1 100644
|
||||
--- a/browser/components/urlbar/UrlbarProvidersManager.sys.mjs
|
||||
+++ b/browser/components/urlbar/UrlbarProvidersManager.sys.mjs
|
||||
@@ -913,6 +913,7 @@ export class Query {
|
||||
@@ -10,3 +10,26 @@ index 08455d8d5da233639ccebc0e77c0810fb4f674c3..78d0e875978b568b79646489c28b125a
|
||||
(!this.context.trimmedSearchString ||
|
||||
(!this.context.searchMode.engineName && !result.autofill))
|
||||
) {
|
||||
@@ -1043,6 +1044,7 @@ function updateSourcesIfEmpty(context) {
|
||||
lazy.UrlbarTokenizer.TYPE.RESTRICT_TITLE,
|
||||
lazy.UrlbarTokenizer.TYPE.RESTRICT_URL,
|
||||
lazy.UrlbarTokenizer.TYPE.RESTRICT_ACTION,
|
||||
+ lazy.UrlbarTokenizer.TYPE.RESTRICT_WORKSPACE,
|
||||
].includes(t.type)
|
||||
);
|
||||
|
||||
@@ -1100,6 +1102,14 @@ function updateSourcesIfEmpty(context) {
|
||||
acceptedSources.push(source);
|
||||
}
|
||||
break;
|
||||
+ case lazy.UrlbarUtils.RESULT_SOURCE.WORKSPACES:
|
||||
+ if (
|
||||
+ restrictTokenType === lazy.UrlbarTokenizer.TYPE.RESTRICT_WORKSPACE ||
|
||||
+ !restrictTokenType
|
||||
+ ) {
|
||||
+ acceptedSources.push(source);
|
||||
+ }
|
||||
+ break;
|
||||
case lazy.UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL:
|
||||
case lazy.UrlbarUtils.RESULT_SOURCE.ADDON:
|
||||
default:
|
||||
|
||||
28
src/browser/components/urlbar/UrlbarTokenizer-sys-mjs.patch
Normal file
28
src/browser/components/urlbar/UrlbarTokenizer-sys-mjs.patch
Normal file
@@ -0,0 +1,28 @@
|
||||
diff --git a/browser/components/urlbar/UrlbarTokenizer.sys.mjs b/browser/components/urlbar/UrlbarTokenizer.sys.mjs
|
||||
index d4af0ee5138a69139b94d898fb07e2345172f025..f750aae3f9f0a849ca009784510575b2b7119e6d 100644
|
||||
--- a/browser/components/urlbar/UrlbarTokenizer.sys.mjs
|
||||
+++ b/browser/components/urlbar/UrlbarTokenizer.sys.mjs
|
||||
@@ -66,6 +66,7 @@ export var UrlbarTokenizer = {
|
||||
// `looksLikeOrigin()` returned `LOOKS_LIKE_ORIGIN.OTHER` for this token. It
|
||||
// may or may not be an origin.
|
||||
POSSIBLE_ORIGIN_BUT_SEARCH_ALLOWED: 12,
|
||||
+ RESTRICT_WORKSPACE: 13,
|
||||
}),
|
||||
|
||||
// The special characters below can be typed into the urlbar to restrict
|
||||
@@ -83,6 +84,7 @@ export var UrlbarTokenizer = {
|
||||
TITLE: "#",
|
||||
URL: "$",
|
||||
ACTION: ">",
|
||||
+ WORKSPACE: "`",
|
||||
}),
|
||||
|
||||
// The keys of characters in RESTRICT that will enter search mode.
|
||||
@@ -97,6 +99,7 @@ export var UrlbarTokenizer = {
|
||||
if (lazy.UrlbarPrefs.get("scotchBonnet.enableOverride")) {
|
||||
keys.push(this.RESTRICT.ACTION);
|
||||
}
|
||||
+ keys.push(this.RESTRICT.WORKSPACE);
|
||||
return new Set(keys);
|
||||
},
|
||||
|
||||
@@ -1,29 +1,50 @@
|
||||
diff --git a/browser/components/urlbar/UrlbarUtils.sys.mjs b/browser/components/urlbar/UrlbarUtils.sys.mjs
|
||||
index 64afd613f454edd7786fcc1e2f307a582e4d5f51..b4af9cc2fbddba2c5229e8ffee7b9c0c06c3e1d0 100644
|
||||
index 64afd613f454edd7786fcc1e2f307a582e4d5f51..50e2dd129d4f2e8f0b07e29639d660cd08ee7318 100644
|
||||
--- a/browser/components/urlbar/UrlbarUtils.sys.mjs
|
||||
+++ b/browser/components/urlbar/UrlbarUtils.sys.mjs
|
||||
@@ -85,6 +85,7 @@ export var UrlbarUtils = {
|
||||
@@ -85,6 +85,8 @@ export var UrlbarUtils = {
|
||||
RESTRICT_SEARCH_KEYWORD: "restrictSearchKeyword",
|
||||
SUGGESTED_INDEX: "suggestedIndex",
|
||||
TAIL_SUGGESTION: "tailSuggestion",
|
||||
+ ZEN_ACTION: "zenAction",
|
||||
+ ZEN_WORKSPACE: "zenWorkspace",
|
||||
}),
|
||||
|
||||
// Defines provider types.
|
||||
@@ -146,6 +147,7 @@ export var UrlbarUtils = {
|
||||
@@ -146,6 +148,8 @@ export var UrlbarUtils = {
|
||||
OTHER_NETWORK: 6,
|
||||
ADDON: 7,
|
||||
ACTIONS: 8,
|
||||
+ ZEN_ACTIONS: 9,
|
||||
+ WORKSPACES: 10,
|
||||
}),
|
||||
|
||||
// Per-result exposure telemetry.
|
||||
@@ -587,6 +589,8 @@ export var UrlbarUtils = {
|
||||
@@ -295,6 +299,14 @@ export var UrlbarUtils = {
|
||||
telemetryLabel: "actions",
|
||||
uiLabel: "urlbar-searchmode-actions",
|
||||
},
|
||||
+ {
|
||||
+ source: this.RESULT_SOURCE.WORKSPACES,
|
||||
+ restrict: lazy.UrlbarTokenizer.RESTRICT.WORKSPACE,
|
||||
+ icon: "chrome://browser/skin/zen-icons/selectable/layers.svg",
|
||||
+ pref: "shortcuts.workspaces",
|
||||
+ telemetryLabel: "workspaces",
|
||||
+ uiLabel: "urlbar-searchmode-workspaces",
|
||||
+ },
|
||||
]);
|
||||
},
|
||||
|
||||
@@ -587,6 +599,12 @@ export var UrlbarUtils = {
|
||||
return this.RESULT_GROUP.HEURISTIC_FALLBACK;
|
||||
case "UrlbarProviderHistoryUrlHeuristic":
|
||||
return this.RESULT_GROUP.HEURISTIC_HISTORY_URL;
|
||||
+ case "ZenUrlbarProviderGlobalActions":
|
||||
+ return this.RESULT_GROUP.ZEN_ACTION;
|
||||
+ if (result.source == this.RESULT_SOURCE.WORKSPACES) {
|
||||
+ return this.RESULT_GROUP.ZEN_WORKSPACE;
|
||||
+ } else {
|
||||
+ return this.RESULT_GROUP.ZEN_ACTION;
|
||||
+ }
|
||||
case "UrlbarProviderOmnibox":
|
||||
return this.RESULT_GROUP.HEURISTIC_OMNIBOX;
|
||||
case "UrlbarProviderRestrictKeywordsAutofill":
|
||||
|
||||
@@ -796,7 +796,8 @@
|
||||
--fp-enabled: 1;
|
||||
}
|
||||
|
||||
#alltabs-button {
|
||||
#alltabs-button,
|
||||
#urlbar-engine-one-off-item-workspaces {
|
||||
list-style-image: url("chrome://browser/skin/tabs.svg") !important;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,3 +5,4 @@
|
||||
[DEFAULT]
|
||||
|
||||
["browser_ub_actions_search.js"]
|
||||
["browser_workspace_restrict_search.js"]
|
||||
|
||||
142
src/zen/tests/ub-actions/browser_workspace_restrict_search.js
Normal file
142
src/zen/tests/ub-actions/browser_workspace_restrict_search.js
Normal file
@@ -0,0 +1,142 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
https://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.defineESModuleGetters(this, {
|
||||
UrlbarTestUtils: "resource://testing-common/UrlbarTestUtils.sys.mjs",
|
||||
UrlbarUtils: "moz-src:///browser/components/urlbar/UrlbarUtils.sys.mjs",
|
||||
});
|
||||
|
||||
UrlbarTestUtils.init(this);
|
||||
|
||||
add_task(async function test_Workspace_Search_OneOff_Pref() {
|
||||
const oneOffSearchButtons = UrlbarTestUtils.getOneOffSearchButtons(window);
|
||||
|
||||
async function openPopupAndWaitForRebuild(value = "") {
|
||||
oneOffSearchButtons.invalidateCache();
|
||||
const rebuildPromise = BrowserTestUtils.waitForEvent(
|
||||
oneOffSearchButtons,
|
||||
"rebuild"
|
||||
);
|
||||
await UrlbarTestUtils.promiseAutocompleteResultPopup({
|
||||
window,
|
||||
waitForFocus,
|
||||
value,
|
||||
});
|
||||
await rebuildPromise;
|
||||
}
|
||||
|
||||
function getWorkspaceShortcut() {
|
||||
return [...oneOffSearchButtons.localButtons].find(
|
||||
button => button.source == UrlbarUtils.RESULT_SOURCE.WORKSPACES
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["zen.urlbar.hide-one-offs", false]],
|
||||
});
|
||||
|
||||
await openPopupAndWaitForRebuild();
|
||||
ok(
|
||||
getWorkspaceShortcut(),
|
||||
"The workspace shortcut should be visible when the pref is enabled"
|
||||
);
|
||||
await UrlbarTestUtils.promisePopupClose(window);
|
||||
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["browser.urlbar.shortcuts.workspaces", false]],
|
||||
});
|
||||
|
||||
try {
|
||||
await openPopupAndWaitForRebuild();
|
||||
ok(
|
||||
!getWorkspaceShortcut(),
|
||||
"The workspace shortcut should be hidden when the pref is disabled"
|
||||
);
|
||||
await UrlbarTestUtils.promisePopupClose(window);
|
||||
} finally {
|
||||
await SpecialPowers.popPrefEnv();
|
||||
}
|
||||
} finally {
|
||||
await SpecialPowers.popPrefEnv();
|
||||
if (UrlbarTestUtils.isPopupOpen(window)) {
|
||||
await UrlbarTestUtils.promisePopupClose(window);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
add_task(async function test_Workspace_Restrict_Search() {
|
||||
const originalWorkspaceId = gZenWorkspaces.activeWorkspace;
|
||||
const workspaceName = "zen-urlbar-workspace-proof-617db8";
|
||||
|
||||
await gZenWorkspaces.createAndSaveWorkspace(workspaceName);
|
||||
|
||||
const createdWorkspace = gZenWorkspaces
|
||||
.getWorkspaces()
|
||||
.find(workspace => workspace.name == workspaceName);
|
||||
ok(createdWorkspace, "Created the workspace used by the urlbar test");
|
||||
|
||||
registerCleanupFunction(async function () {
|
||||
if (UrlbarTestUtils.isPopupOpen(window)) {
|
||||
await UrlbarTestUtils.promisePopupClose(window, () =>
|
||||
EventUtils.synthesizeKey("KEY_Escape")
|
||||
);
|
||||
}
|
||||
if (gZenWorkspaces.activeWorkspace != originalWorkspaceId) {
|
||||
await gZenWorkspaces.changeWorkspace(originalWorkspaceId);
|
||||
}
|
||||
if (
|
||||
gZenWorkspaces
|
||||
.getWorkspaces()
|
||||
.some(workspace => workspace.uuid == createdWorkspace.uuid)
|
||||
) {
|
||||
await gZenWorkspaces.removeWorkspace(createdWorkspace.uuid);
|
||||
}
|
||||
});
|
||||
|
||||
await gZenWorkspaces.changeWorkspace(originalWorkspaceId);
|
||||
|
||||
await UrlbarTestUtils.promiseAutocompleteResultPopup({
|
||||
window,
|
||||
waitForFocus,
|
||||
value: "` " + workspaceName,
|
||||
});
|
||||
// Wait for the second search started when the typed token enters search mode.
|
||||
await UrlbarTestUtils.promiseSearchComplete(window);
|
||||
ok(gURLBar.searchMode, "The urlbar should enter search mode");
|
||||
Assert.equal(
|
||||
gURLBar.searchMode.source,
|
||||
UrlbarUtils.RESULT_SOURCE.WORKSPACES,
|
||||
"The typed token should enter workspace search mode"
|
||||
);
|
||||
Assert.equal(
|
||||
gURLBar.searchMode.entry,
|
||||
"typed",
|
||||
"The workspace search mode should be entered by typing the token"
|
||||
);
|
||||
Assert.equal(gURLBar.value, workspaceName, "The token should be stripped");
|
||||
|
||||
const resultCount = UrlbarTestUtils.getResultCount(window);
|
||||
ok(resultCount > 0, "Should show at least one workspace result");
|
||||
|
||||
const resultDetails = [];
|
||||
for (let i = 0; i < resultCount; i++) {
|
||||
resultDetails.push(await UrlbarTestUtils.getDetailsOfResultAt(window, i));
|
||||
}
|
||||
|
||||
ok(
|
||||
resultDetails.every(
|
||||
({ result, source }) =>
|
||||
source == UrlbarUtils.RESULT_SOURCE.WORKSPACES &&
|
||||
result.providerName == "ZenUrlbarProviderGlobalActions"
|
||||
),
|
||||
"Typing the workspace token should limit results to workspace actions"
|
||||
);
|
||||
Assert.equal(
|
||||
resultDetails[0].result.payload.prettyName,
|
||||
workspaceName,
|
||||
"The matching workspace should be shown first"
|
||||
);
|
||||
});
|
||||
@@ -155,6 +155,7 @@ export class ZenUrlbarProviderGlobalActions extends UrlbarProvider {
|
||||
*/
|
||||
async isActive(queryContext) {
|
||||
return (
|
||||
queryContext.searchMode?.source == UrlbarUtils.RESULT_SOURCE.WORKSPACES ||
|
||||
queryContext.searchMode?.source ==
|
||||
UrlbarUtils.RESULT_SOURCE.ZEN_ACTIONS ||
|
||||
(lazy.enabledPref &&
|
||||
@@ -241,10 +242,13 @@ export class ZenUrlbarProviderGlobalActions extends UrlbarProvider {
|
||||
*
|
||||
* @param {string} query The user's search query.
|
||||
* @param {boolean} isPrefixed Whether the query is prefixed.
|
||||
* @param {boolean} isWorkspaceSearch Whether this is a workspace search query
|
||||
*/
|
||||
async #findMatchingActions(query, isPrefixed) {
|
||||
async #findMatchingActions(query, isPrefixed, isWorkspaceSearch) {
|
||||
const window = lazy.BrowserWindowTracker.getTopWindow();
|
||||
const actions = await this.#getAvailableActions(window);
|
||||
const actions = isWorkspaceSearch
|
||||
? this.#getWorkspaceActions(window)
|
||||
: await this.#getAvailableActions(window);
|
||||
let results = [];
|
||||
for (let action of actions) {
|
||||
if (isPrefixed && query.length < 1) {
|
||||
@@ -341,13 +345,21 @@ export class ZenUrlbarProviderGlobalActions extends UrlbarProvider {
|
||||
|
||||
async startQuery(queryContext, addCallback) {
|
||||
const query = queryContext.trimmedLowerCaseSearchString;
|
||||
const isWorkspaceSearch =
|
||||
queryContext.searchMode?.source == UrlbarUtils.RESULT_SOURCE.WORKSPACES;
|
||||
const isPrefixed =
|
||||
isWorkspaceSearch ||
|
||||
queryContext.searchMode?.source == UrlbarUtils.RESULT_SOURCE.ZEN_ACTIONS;
|
||||
|
||||
if (!query && !isPrefixed) {
|
||||
return;
|
||||
}
|
||||
|
||||
const actionsResults = await this.#findMatchingActions(query, isPrefixed);
|
||||
const actionsResults = await this.#findMatchingActions(
|
||||
query,
|
||||
isPrefixed,
|
||||
isWorkspaceSearch
|
||||
);
|
||||
if (!actionsResults.length) {
|
||||
return;
|
||||
}
|
||||
@@ -361,9 +373,12 @@ export class ZenUrlbarProviderGlobalActions extends UrlbarProvider {
|
||||
zenCommand: action.command,
|
||||
dynamicType: DYNAMIC_TYPE_NAME,
|
||||
zenAction: true,
|
||||
query: isPrefixed
|
||||
? action.label.trimStart()
|
||||
: queryContext.searchString,
|
||||
// eslint-disable-next-line no-nested-ternary
|
||||
query: isWorkspaceSearch
|
||||
? action.extraPayload.prettyName
|
||||
: isPrefixed
|
||||
? action.label.trimStart()
|
||||
: queryContext.searchString,
|
||||
icon: action.icon,
|
||||
shortcutContent:
|
||||
ownerGlobal.gZenKeyboardShortcutsManager.getShortcutDisplayFromCommand(
|
||||
@@ -378,7 +393,9 @@ export class ZenUrlbarProviderGlobalActions extends UrlbarProvider {
|
||||
!isPrefixed;
|
||||
let result = new lazy.UrlbarResult({
|
||||
type: UrlbarUtils.RESULT_TYPE.DYNAMIC,
|
||||
source: UrlbarUtils.RESULT_SOURCE.ZEN_ACTIONS,
|
||||
source: isWorkspaceSearch
|
||||
? UrlbarUtils.RESULT_SOURCE.WORKSPACES
|
||||
: UrlbarUtils.RESULT_SOURCE.ZEN_ACTIONS,
|
||||
payload,
|
||||
highlights: payloadHighlights,
|
||||
heuristic: shouldBePrioritized,
|
||||
@@ -398,7 +415,7 @@ export class ZenUrlbarProviderGlobalActions extends UrlbarProvider {
|
||||
zenUrlbarResultsLearner
|
||||
.sortCommandsByPriority(finalResults)
|
||||
.forEach(result => {
|
||||
if (isPrefixed && i === 0 && query.length > 1) {
|
||||
if (isPrefixed && !isWorkspaceSearch && i === 0 && query.length > 1) {
|
||||
result.heuristic = true;
|
||||
delete result.suggestedIndex;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user