Bug 1946523 - STG - Step 1 UI migration r=fluent-reviewers,desktop-theme-reviewers,tabbrowser-reviewers,dao,bolsson

Adding additional UI elements and filling out state machine with actualy UI updates. Some functions are stubbed out while waiting on ML to have API up on central. These UI changes should have no change to current UI if pref is turned off.

Differential Revision: https://phabricator.services.mozilla.com/D237277
This commit is contained in:
Nick Grato
2025-02-14 23:37:56 +00:00
parent 06446e1ecf
commit 6cf0bc44df
7 changed files with 677 additions and 78 deletions

View File

@@ -30,15 +30,8 @@
"gray",
"red",
];
static markup = `
<panel
type="arrow"
class="panel tab-group-editor-panel"
orient="vertical"
role="dialog"
ignorekeys="true"
norolluponanchor="true">
static headerSection = /*html*/ `
<html:div class="panel-header">
<html:h1
id="tab-group-editor-title-create"
@@ -51,46 +44,9 @@
data-l10n-id="tab-group-editor-title-edit">
</html:h1>
</html:div>
`;
<toolbarseparator />
<html:div
class="panel-body
tab-group-editor-name">
<html:label
for="tab-group-name"
data-l10n-id="tab-group-editor-name-label">
</html:label>
<html:input
id="tab-group-name"
type="text"
name="tab-group-name"
value=""
data-l10n-id="tab-group-editor-name-field"
/>
</html:div>
<html:div
class="panel-body tab-group-editor-swatches"
role="radiogroup"
data-l10n-id="tab-group-editor-color-selector"
/>
<html:moz-button-group
class="panel-body tab-group-create-actions tab-group-create-mode-only">
<html:moz-button
id="tab-group-editor-button-cancel"
data-l10n-id="tab-group-editor-cancel">
</html:moz-button>
<html:moz-button
type="primary"
id="tab-group-editor-button-create"
data-l10n-id="tab-group-editor-done">
</html:moz-button>
</html:moz-button-group>
<toolbarseparator class="tab-group-edit-mode-only" />
static editActions = /*html*/ `
<html:div
class="panel-body tab-group-edit-actions tab-group-edit-mode-only">
<toolbarbutton
@@ -118,7 +74,7 @@
data-l10n-id="tab-group-editor-action-ungroup">
</toolbarbutton>
</html:div>
<toolbarseparator class="tab-group-edit-mode-only" />
<html:div class="tab-group-edit-mode-only panel-body tab-group-delete">
@@ -129,7 +85,163 @@
data-l10n-id="tab-group-editor-action-delete">
</toolbarbutton>
</html:div>
`;
static suggestionsHeader = /*html*/ `
<html:div id="tab-group-suggestions-heading" hidden="true">
<html:div class="panel-header">
<html:h1 data-l10n-id="tab-group-editor-title-suggest"></html:h1>
</html:div>
<toolbarseparator />
</html:div>
`;
static suggestionsSection = /*html*/ `
<html:div id="tab-group-suggestions-container" hidden="true">
<html:div
id="tab-group-suggestions-header"
data-l10n-id="tab-group-editor-suggestions-header">
</html:div>
<html:div id="tab-group-suggestions"></html:div>
<html:moz-button
id="tab-group-select-toggle"
data-l10n-id="tab-group-editor-deselect-suggestions"
size="small"
data-state="deselect">
</html:moz-button>
<html:moz-button-group class="panel-body tab-group-create-actions">
<html:moz-button
id="tab-group-cancel-suggestions-button"
data-l10n-id="tab-group-editor-cancel">
</html:moz-button>
<html:moz-button
type="primary"
id="tab-group-create-suggestions-button"
data-l10n-id="tab-group-editor-done">
</html:moz-button>
</html:moz-button-group>
</html:div>
`;
static suggestionsButton = /*html*/ `
<html:moz-button
hidden="true"
id="tab-group-suggestion-button"
type="icon ghost"
data-l10n-id="tab-group-editor-smart-suggest-button-create">
</html:moz-button>
`;
static loadingSection = /*html*/ `
<html:div id="tab-group-suggestions-loading" hidden="true">
<html:div
class="tab-group-suggestions-loading-header"
data-l10n-id="tab-group-suggestions-loading-header">
</html:div>
<html:div class="tab-group-suggestions-loading-block"></html:div>
<html:div class="tab-group-suggestions-loading-block"></html:div>
<html:div class="tab-group-suggestions-loading-block"></html:div>
</html:div>
`;
static defaultActions = /*html*/ `
<html:moz-button-group
class="panel-body tab-group-create-actions tab-group-create-mode-only"
id="tab-group-default-actions">
<html:moz-button
id="tab-group-editor-button-cancel"
data-l10n-id="tab-group-editor-cancel">
</html:moz-button>
<html:moz-button
type="primary"
id="tab-group-editor-button-create"
data-l10n-id="tab-group-editor-done">
</html:moz-button>
</html:moz-button-group>
`;
static loadingActions = /*html*/ `
<html:moz-button-group id="tab-group-suggestions-load-actions" hidden="true">
<html:moz-button
id="tab-group-suggestions-load-cancel"
data-l10n-id="tab-group-editor-cancel">
</html:moz-button>
</html:moz-button-group>
`;
static markup = /*html*/ `
<panel
type="arrow"
class="panel tab-group-editor-panel"
orient="vertical"
role="dialog"
ignorekeys="true"
norolluponanchor="true">
<html:div id="tab-group-main">
${this.headerSection}
<toolbarseparator />
<html:div
class="panel-body
tab-group-editor-name">
<html:label
for="tab-group-name"
data-l10n-id="tab-group-editor-name-label">
</html:label>
<html:input
id="tab-group-name"
type="text"
name="tab-group-name"
value=""
data-l10n-id="tab-group-editor-name-field"
/>
</html:div>
<html:div
class="panel-body tab-group-editor-swatches"
role="radiogroup"
data-l10n-id="tab-group-editor-color-selector"
/>
<toolbarseparator class="tab-group-edit-mode-only"/>
${this.editActions}
<toolbarseparator id="tab-group-suggestions-separator" hidden="true"/>
${this.suggestionsButton}
<html:p
hidden="true"
id="tab-group-suggestions-disclaimer"
data-l10n-id="tab-group-suggestions-disclaimer">
<a data-l10n-name="support" href="#"></a>
</html:p>
<html:moz-button
hidden="true"
disabled="true"
type="icon ghost"
id="tab-group-suggestions-message"
data-l10n-id="tab-group-editor-no-tabs-found">
</html:moz-button>
${this.defaultActions}
</html:div>
${this.suggestionsHeader}
${this.loadingSection}
${this.loadingActions}
${this.suggestionsSection}
</panel>
`;
@@ -158,6 +270,7 @@
ERROR: 11,
};
#tabGroupMain;
#activeGroup;
#cancelButton;
#createButton;
@@ -167,7 +280,25 @@
#panel;
#swatches;
#swatchesContainer;
#defaultActions;
#suggestionState = MozTabbrowserTabGroupMenu.State.CREATE_STANDARD_INITIAL;
#suggestionsHeading;
#suggestionsHeader;
#suggestionsContainer;
#suggestions;
#suggestionButton;
#cancelSuggestionsButton;
#createSuggestionsButton;
#suggestionsLoading;
#selectSuggestionsToggle;
#suggestionsMessage;
#suggestionsDisclaimer;
#selectedSuggestedTabs = [];
#suggestedTabs = [];
#suggestionsLoadActions;
#suggestionsLoadCancel;
#suggestionsSeparator;
#smartTabGroupingManager;
constructor() {
super();
@@ -195,6 +326,11 @@
this.#swatchesContainer = this.querySelector(
".tab-group-editor-swatches"
);
this.#defaultActions = this.querySelector("#tab-group-default-actions");
this.#tabGroupMain = this.querySelector("#tab-group-main");
this.#initSuggestions();
this.#populateSwatches();
this.#cancelButton.addEventListener("click", () => {
@@ -211,6 +347,22 @@
}
});
/**
* Check if the smart suggest button should be shown
* If there are no ungrouped tabs, the button should be hidden
*/
this.canShowAIUserInterface = () => {
const { tabs } = gBrowser;
let show = false;
tabs.forEach(tab => {
if (tab.group === null) {
show = true;
}
});
return show;
};
document
.getElementById("tabGroupEditor_addNewTabInGroup")
.addEventListener("command", () => {
@@ -247,6 +399,78 @@
this.#swatchesContainer.addEventListener("change", this);
}
#initSuggestions() {
const AI_ICON = "chrome://global/skin/icons/highlights.svg";
const { SmartTabGroupingManager } = ChromeUtils.importESModule(
"resource:///modules/SmartTabGrouping.sys.mjs"
);
this.#smartTabGroupingManager = new SmartTabGroupingManager();
// Init Suggestion Button
this.#suggestionButton = this.querySelector(
"#tab-group-suggestion-button"
);
this.#suggestionButton.iconSrc = AI_ICON;
this.#suggestionButton.addEventListener("click", () => {
this.#handleSmartSuggest();
});
// Init Suggestions UI
this.#suggestionsHeading = this.querySelector(
"#tab-group-suggestions-heading"
);
this.#suggestionsHeader = this.querySelector(
"#tab-group-suggestions-header"
);
this.#suggestionsContainer = this.querySelector(
"#tab-group-suggestions-container"
);
this.#suggestions = this.querySelector("#tab-group-suggestions");
this.#selectSuggestionsToggle = this.querySelector(
"#tab-group-select-toggle"
);
this.#selectSuggestionsToggle.addEventListener("click", () => {
this.#handleSelectToggle();
});
this.#suggestionsMessage = this.querySelector(
"#tab-group-suggestions-message"
);
this.#suggestionsMessage.iconSrc = AI_ICON;
this.#suggestionsDisclaimer = this.querySelector(
"#tab-group-suggestions-disclaimer"
);
this.#createSuggestionsButton = this.querySelector(
"#tab-group-create-suggestions-button"
);
this.#createSuggestionsButton.addEventListener("click", () => {
this.activeGroup.addTabs(this.#selectedSuggestedTabs);
this.close(true);
});
this.#cancelSuggestionsButton = this.querySelector(
"#tab-group-cancel-suggestions-button"
);
this.#cancelSuggestionsButton.addEventListener("click", () => {
this.close();
});
this.#suggestionsSeparator = this.querySelector(
"#tab-group-suggestions-separator"
);
// Init Loading UI
this.#suggestionsLoading = this.querySelector(
"#tab-group-suggestions-loading"
);
this.#suggestionsLoadActions = this.querySelector(
"#tab-group-suggestions-load-actions"
);
this.#suggestionsLoadCancel = this.querySelector(
"#tab-group-suggestions-load-cancel"
);
this.#suggestionsLoadCancel.addEventListener("click", () => {
this.#handleLoadSuggestionsCancel();
});
}
#populateSwatches() {
this.#clearSwatches();
for (let colorCode of MozTabbrowserTabGroupMenu.COLORS) {
@@ -348,11 +572,10 @@
openCreateModal(group) {
this.activeGroup = group;
this.createMode = true;
this.suggestionState =
MozTabbrowserTabGroupMenu.State.CREATE_STANDARD_INITIAL;
if (lazy.smartTabGroupsEnabled) {
//TODO: set appropriate state
}
this.suggestionState = lazy.smartTabGroupsEnabled
? MozTabbrowserTabGroupMenu.State.CREATE_AI_INITIAL
: MozTabbrowserTabGroupMenu.State.CREATE_STANDARD_INITIAL;
this.#panel.openPopup(group.firstChild, {
position: this.#panelPosition,
});
@@ -361,11 +584,10 @@
openEditModal(group) {
this.activeGroup = group;
this.createMode = false;
this.suggestionState =
MozTabbrowserTabGroupMenu.State.EDIT_STANDARD_INITIAL;
if (lazy.smartTabGroupsEnabled) {
//TODO: set appropriate state
}
this.suggestionState = lazy.smartTabGroupsEnabled
? MozTabbrowserTabGroupMenu.State.EDIT_AI_INITIAL
: MozTabbrowserTabGroupMenu.State.EDIT_STANDARD_INITIAL;
this.#panel.openPopup(group.firstChild, {
position: this.#panelPosition,
});
@@ -419,6 +641,7 @@
}
}
this.activeGroup = null;
this.#smartTabGroupingManager.terminateProcess();
}
on_keypress(event) {
@@ -487,8 +710,192 @@
this.#renderSuggestionState();
}
#handleLoadSuggestionsCancel() {
// TODO look into actually canceling any processes
this.suggestionState = this.createMode
? MozTabbrowserTabGroupMenu.State.CREATE_AI_INITIAL
: MozTabbrowserTabGroupMenu.State.EDIT_AI_INITIAL;
}
#handleSelectToggle() {
const currentState =
this.#selectSuggestionsToggle.getAttribute("data-state");
const isDeselect = currentState === "deselect";
isDeselect ? this.#handleDeselectAll() : this.#handleSelectAll();
const newState = isDeselect ? "select" : "deselect";
this.#setSelectToggleState(newState);
}
#handleSelectAll() {
document
.querySelectorAll(".tab-group-suggestion-checkbox")
.forEach(checkbox => {
checkbox.checked = true;
});
// Reset selected tabs to all suggested tabs
this.#selectedSuggestedTabs = this.#suggestedTabs;
}
#handleDeselectAll() {
document
.querySelectorAll(".tab-group-suggestion-checkbox")
.forEach(checkbox => {
checkbox.checked = false;
});
this.#selectedSuggestedTabs = [];
}
async #handleSmartSuggest() {
// Loading
this.suggestionState = MozTabbrowserTabGroupMenu.State.LOADING;
const tabs = await this.#smartTabGroupingManager.smartTabGroupingForGroup(
this.activeGroup,
gBrowser.tabs
);
if (!tabs.length) {
// No un-grouped tabs found
this.suggestionState = this.#createMode
? MozTabbrowserTabGroupMenu.State.CREATE_AI_WITH_NO_SUGGESTIONS
: MozTabbrowserTabGroupMenu.State.EDIT_AI_WITH_NO_SUGGESTIONS;
return;
}
this.#selectedSuggestedTabs = tabs;
this.#suggestedTabs = tabs;
tabs.forEach((tab, index) => {
this.#createRow(tab, index);
});
this.suggestionState = this.#createMode
? MozTabbrowserTabGroupMenu.State.CREATE_AI_WITH_SUGGESTIONS
: MozTabbrowserTabGroupMenu.State.EDIT_AI_WITH_SUGGESTIONS;
}
#createRow(tab, index) {
// Create Row
let row = document.createXULElement("toolbaritem");
row.setAttribute("context", "tabContextMenu");
row.setAttribute("id", `tab-bar-${index}`);
// Create Checkbox
let checkbox = document.createXULElement("checkbox");
checkbox.value = tab;
checkbox.setAttribute("checked", true);
checkbox.classList.add("tab-group-suggestion-checkbox");
checkbox.addEventListener("CheckboxStateChange", e => {
const isChecked = e.target.checked;
const currentTab = e.target.value;
if (isChecked) {
this.#selectedSuggestedTabs.push(currentTab);
} else {
this.#selectedSuggestedTabs = this.#selectedSuggestedTabs.filter(
t => t != currentTab
);
}
});
row.appendChild(checkbox);
// Create Row Label
let label = document.createXULElement("toolbarbutton");
label.classList.add(
"all-tabs-button",
"subviewbutton",
"subviewbutton-iconic",
"tab-group-suggestion-label"
);
label.setAttribute("flex", "1");
label.setAttribute("crop", "end");
label.label = tab.label;
label.image = tab.image;
label.disabled = true;
row.appendChild(label);
// Apply Row to Suggestions
this.#suggestions.appendChild(row);
}
/**
* Set the state of the select toggle button
* @param {string} "select" | "deselect"
*/
#setSelectToggleState(state) {
this.#selectSuggestionsToggle.setAttribute("data-state", state);
this.#selectSuggestionsToggle.setAttribute(
"data-l10n-id",
`tab-group-editor-${state}-suggestions`
);
}
/**
* Element visibility utility function.
* Toggles the `hidden` attribute of a DOM element.
*
* @param {HTMLElement|XULElement} element - The DOM element to show/hide.
* @param {boolean} shouldShow - Whether the element should be shown (true) or hidden (false).
*/
#setElementVisibility(element, shouldShow) {
element.hidden = !shouldShow;
}
#showDefaultTabGroupActions(value) {
this.#setElementVisibility(this.#defaultActions, value);
}
#showSmartSuggestionsContainer(value) {
this.#setElementVisibility(this.#suggestionsContainer, value);
}
#showSuggestionButton(value) {
this.#setElementVisibility(this.#suggestionButton, value);
}
#showSuggestionMessage(value) {
this.#setElementVisibility(this.#suggestionsMessage, value);
}
#showSuggestionsDisclaimer(value) {
this.#setElementVisibility(this.#suggestionsDisclaimer, value);
}
#showSuggestionsSeparator(value) {
this.#setElementVisibility(this.#suggestionsSeparator, value);
}
#setLoadingState(value) {
this.#setElementVisibility(this.#suggestionsLoadActions, value);
this.#setElementVisibility(this.#suggestionsLoading, value);
}
#setSuggestionsButtonCreateModeState(value) {
const translationString = value
? "tab-group-editor-smart-suggest-button-create"
: "tab-group-editor-smart-suggest-button-edit";
this.#suggestionButton.setAttribute("data-l10n-id", translationString);
}
/**
* Unique state setter for a "3rd" panel state while in Edit Mode
* that just shows suggestions and hides the majority of the panel
* @param {boolean} value
*/
#setEditModeSuggestionState(value) {
this.#setElementVisibility(this.#suggestionsHeader, !value);
this.#setElementVisibility(this.#tabGroupMain, !value);
this.#setElementVisibility(this.#suggestionsHeading, value);
}
#resetCommonUI() {
// TODO - has commun UI reset logic
this.#setLoadingState(false);
this.#setEditModeSuggestionState(false);
this.#suggestedTabs = [];
this.#selectedSuggestedTabs = [];
this.#suggestions.innerHTML = "";
this.#showSmartSuggestionsContainer(false);
}
#renderSuggestionState() {
@@ -496,64 +903,111 @@
// CREATE STANDARD INITIAL
case MozTabbrowserTabGroupMenu.State.CREATE_STANDARD_INITIAL:
this.#resetCommonUI();
//TODO
this.#showDefaultTabGroupActions(true);
this.#showSuggestionButton(false);
this.#showSuggestionMessage(false);
this.#showSuggestionsDisclaimer(false);
this.#showSuggestionsSeparator(false);
break;
//CREATE AI INITIAL
case MozTabbrowserTabGroupMenu.State.CREATE_AI_INITIAL:
this.#resetCommonUI();
//TODO
this.#showSuggestionButton(true);
this.#showDefaultTabGroupActions(true);
this.#showSuggestionMessage(false);
this.#setSelectToggleState("deselect");
this.#showSuggestionsDisclaimer(true);
this.#setSuggestionsButtonCreateModeState(true);
this.#showSuggestionsSeparator(true);
break;
// CREATE AI INITIAL SUGGESTIONS DISABLED
case MozTabbrowserTabGroupMenu.State
.CREATE_AI_INITIAL_SUGGESTIONS_DISABLED:
this.#resetCommonUI();
//TODO
this.#showSuggestionButton(false);
this.#showSuggestionsDisclaimer(false);
this.#showSuggestionMessage(true);
this.#showDefaultTabGroupActions(true);
this.#showSuggestionsSeparator(true);
break;
// CREATE AI WITH SUGGESTIONS
case MozTabbrowserTabGroupMenu.State.CREATE_AI_WITH_SUGGESTIONS:
//TODO
this.#setLoadingState(false);
this.#showSmartSuggestionsContainer(true);
this.#showSuggestionButton(false);
this.#showSuggestionsSeparator(true);
this.$showDefaultTabGroupActions(false);
break;
// CREATE AI WITH NO SUGGESTIONS
case MozTabbrowserTabGroupMenu.State.CREATE_AI_WITH_NO_SUGGESTIONS:
//TODO
this.#setLoadingState(false);
this.#showSuggestionMessage(true);
this.#showDefaultTabGroupActions(true);
this.#showSuggestionButton(false);
this.#showSuggestionsSeparator(true);
break;
// EDIT STANDARD INITIAL
case MozTabbrowserTabGroupMenu.State.EDIT_STANDARD_INITIAL:
this.#resetCommonUI();
//TODO
this.#showSuggestionButton(false);
this.#showSuggestionMessage(false);
this.#showDefaultTabGroupActions(false);
this.#showSuggestionsDisclaimer(false);
this.#showSuggestionsSeparator(false);
break;
// EDIT AI INITIAL
case MozTabbrowserTabGroupMenu.State.EDIT_AI_INITIAL:
this.#resetCommonUI();
//TODO
this.#showSuggestionMessage(false);
this.#setSelectToggleState("deselect");
this.#showSuggestionButton(true);
this.#showDefaultTabGroupActions(false);
this.#showSuggestionsDisclaimer(false);
this.#setSuggestionsButtonCreateModeState(false);
this.#showSuggestionsSeparator(true);
break;
// EDIT AI INITIAL SUGGESTIONS DISABLED
case MozTabbrowserTabGroupMenu.State
.EDIT_AI_INITIAL_SUGGESTIONS_DISABLED:
this.#resetCommonUI();
//TODO
this.#showSuggestionMessage(true);
this.#showSuggestionButton(false);
this.#showDefaultTabGroupActions(false);
this.#showSuggestionsDisclaimer(false);
this.#showSuggestionsSeparator(true);
break;
// EDIT AI WITH SUGGESTIONS
case MozTabbrowserTabGroupMenu.State.EDIT_AI_WITH_SUGGESTIONS:
//TODO
this.#setLoadingState(false);
this.#showSmartSuggestionsContainer(true);
this.#setEditModeSuggestionState(true);
this.#showSuggestionsSeparator(false);
break;
// EDIT AI WITH NO SUGGESTIONS
case MozTabbrowserTabGroupMenu.State.EDIT_AI_WITH_NO_SUGGESTIONS:
//TODO
this.#setLoadingState(false);
this.#showSuggestionMessage(true);
this.#showSuggestionsSeparator(true);
break;
// LOADING
case MozTabbrowserTabGroupMenu.State.LOADING:
//TODO
this.#showDefaultTabGroupActions(false);
this.#showSuggestionButton(false);
this.#showSuggestionsDisclaimer(false);
this.#showSuggestionMessage(false);
this.#setLoadingState(true);
this.#showSuggestionsSeparator(true);
this.#showDefaultTabGroupActions(false);
break;
// ERROR