diff --git a/packages/fiori/cypress/specs/UserSettingsDialog.cy.tsx b/packages/fiori/cypress/specs/UserSettingsDialog.cy.tsx
index 7c06af057480e..ae1948cfb570b 100644
--- a/packages/fiori/cypress/specs/UserSettingsDialog.cy.tsx
+++ b/packages/fiori/cypress/specs/UserSettingsDialog.cy.tsx
@@ -1498,3 +1498,97 @@ describe("F6 Navigation", () => {
.should("be.focused");
});
});
+
+describe("Save mode", () => {
+ it("renders the default single Close button when saveMode is not set", () => {
+ cy.mount(
+
+
+
+
+ );
+ cy.get("[ui5-user-settings-dialog]").shadow().find("[ui5-toolbar]").as("toolbar");
+ cy.get("@toolbar").find("[ui5-toolbar-button]").should("have.length", 1);
+ cy.get("@toolbar").find("[ui5-toolbar-button]").should("have.attr", "design", "Transparent");
+ });
+
+ it("renders Save (Emphasized) + Cancel buttons when saveMode is set", () => {
+ cy.mount(
+
+
+
+
+ );
+ cy.get("[ui5-user-settings-dialog]").shadow().find("[ui5-toolbar]").as("toolbar");
+ cy.get("@toolbar").find("[ui5-toolbar-button]").should("have.length", 2);
+ cy.get("@toolbar").find("[ui5-toolbar-button]").eq(0).should("have.attr", "design", "Emphasized");
+ cy.get("@toolbar").find("[ui5-toolbar-button]").eq(1).should("have.attr", "design", "Transparent");
+ });
+
+ it("fires the save event when the Save button is clicked", () => {
+ cy.mount(
+
+
+
+
+ );
+ cy.get("[ui5-user-settings-dialog]").as("dialog");
+ cy.get("@dialog").then($d => {
+ $d.get(0).addEventListener("save", cy.stub().as("saveEv"));
+ });
+ cy.get("@dialog").shadow().find("[ui5-toolbar]")
+ .find("[ui5-toolbar-button]").eq(0)
+ .shadow().find("[ui5-button]").click();
+ cy.get("@saveEv").should("have.been.calledOnce");
+ });
+
+ it("fires the cancel event when the Cancel button is clicked", () => {
+ cy.mount(
+
+
+
+
+ );
+ cy.get("[ui5-user-settings-dialog]").as("dialog");
+ cy.get("@dialog").then($d => {
+ $d.get(0).addEventListener("cancel", cy.stub().as("cancelEv"));
+ });
+ cy.get("@dialog").shadow().find("[ui5-toolbar]")
+ .find("[ui5-toolbar-button]").eq(1)
+ .shadow().find("[ui5-button]").click();
+ cy.get("@cancelEv").should("have.been.calledOnce");
+ });
+
+ it("does not close the dialog automatically on Save or Cancel", () => {
+ cy.mount(
+
+
+
+
+ );
+ cy.get("[ui5-user-settings-dialog]").as("dialog");
+ cy.get("@dialog").shadow().find("[ui5-toolbar]")
+ .find("[ui5-toolbar-button]").eq(0)
+ .shadow().find("[ui5-button]").click();
+ cy.get("@dialog").should("have.attr", "open");
+ cy.get("@dialog").shadow().find("[ui5-toolbar]")
+ .find("[ui5-toolbar-button]").eq(1)
+ .shadow().find("[ui5-button]").click();
+ cy.get("@dialog").should("have.attr", "open");
+ });
+
+ it("still fires before-close on ESC in saveMode", () => {
+ cy.mount(
+
+
+
+
+ );
+ cy.get("[ui5-user-settings-dialog]").as("dialog");
+ cy.get("@dialog").then($d => {
+ $d.get(0).addEventListener("before-close", cy.stub().as("beforeClose"));
+ });
+ cy.realPress("Escape");
+ cy.get("@beforeClose").should("have.been.calledOnce");
+ });
+});
diff --git a/packages/fiori/src/UserSettingsDialog.ts b/packages/fiori/src/UserSettingsDialog.ts
index 50833bb02c9f5..0304137b0604d 100644
--- a/packages/fiori/src/UserSettingsDialog.ts
+++ b/packages/fiori/src/UserSettingsDialog.ts
@@ -22,6 +22,8 @@ import {
USER_SETTINGS_DIALOG_ACCESSIBLE_NAME,
USER_SETTINGS_LIST_ARIA_ROLE_DESC,
USER_SETTINGS_DIALOG_CLOSE_BUTTON_TEXT,
+ USER_SETTINGS_DIALOG_SAVE_BUTTON_TEXT,
+ USER_SETTINGS_DIALOG_CANCEL_BUTTON_TEXT,
USER_SETTINGS_DIALOG_NO_SEARCH_RESULTS_TEXT,
} from "./generated/i18n/i18n-defaults.js";
@@ -63,13 +65,16 @@ type UserSettingsBeforeCloseEventDetail = PopupBeforeCloseEventDetail;
})
/**
- * Fired when a settings dialog is open.
+ * Fired when the settings dialog is opened.
* @public
*/
@event("open")
/**
* Fired before the settings dialog is closed.
+ *
+ * **Note:** This event is cancelable via `preventDefault()`, allowing the application to keep the
+ * dialog open — for example, to prompt the user about unsaved changes before dismissal.
* @public
*/
@event("before-close", {
@@ -77,17 +82,35 @@ type UserSettingsBeforeCloseEventDetail = PopupBeforeCloseEventDetail;
})
/**
- * Fired when a settings dialog is closed.
+ * Fired when the settings dialog is closed.
* @public
*/
@event("close")
+/**
+ * Fired when the Save button in the footer is clicked.
+ * The dialog does not close automatically — the application is responsible
+ * for closing it after persisting the changes.
+ * @public
+ */
+@event("save")
+
+/**
+ * Fired when the Cancel button in the footer is clicked.
+ * The dialog does not close automatically — the application is responsible
+ * for closing it after discarding the changes.
+ * @public
+ */
+@event("cancel")
+
class UserSettingsDialog extends UI5Element {
eventDetails!: {
"selection-change": UserSettingsItemSelectEventDetail,
"open": void,
"before-close": UserSettingsBeforeCloseEventDetail,
"close": void,
+ "save": void,
+ "cancel": void,
};
/**
* Defines, if the User Settings Dialog is opened.
@@ -117,6 +140,20 @@ class UserSettingsDialog extends UI5Element {
@property({ type: Boolean })
showSearchField = false;
+ /**
+ * Defines whether the dialog offers Save and Cancel actions in its footer.
+ *
+ * When true, the footer renders a Save (Emphasized) and a Cancel button
+ * instead of the default Close button. Save and Cancel each fire a
+ * corresponding event; the application is responsible for closing the
+ * dialog (typically after persisting or discarding the changes).
+ *
+ * @default false
+ * @public
+ */
+ @property({ type: Boolean })
+ saveMode = false;
+
/**
* Defines the user settings items.
*
@@ -295,6 +332,12 @@ class UserSettingsDialog extends UI5Element {
get closeButtonText() {
return UserSettingsDialog.i18nBundle.getText(USER_SETTINGS_DIALOG_CLOSE_BUTTON_TEXT);
}
+ get saveButtonText() {
+ return UserSettingsDialog.i18nBundle.getText(USER_SETTINGS_DIALOG_SAVE_BUTTON_TEXT);
+ }
+ get cancelButtonText() {
+ return UserSettingsDialog.i18nBundle.getText(USER_SETTINGS_DIALOG_CANCEL_BUTTON_TEXT);
+ }
get noSearchResultsText() {
return UserSettingsDialog.i18nBundle.getText(USER_SETTINGS_DIALOG_NO_SEARCH_RESULTS_TEXT);
}
@@ -315,6 +358,14 @@ class UserSettingsDialog extends UI5Element {
}
}
+ _handleSaveButtonClick() {
+ this.fireDecoratorEvent("save");
+ }
+
+ _handleCancelButtonClick() {
+ this.fireDecoratorEvent("cancel");
+ }
+
_handleCollapseClick() {
this._collapsed = false;
}
diff --git a/packages/fiori/src/UserSettingsDialogTemplate.tsx b/packages/fiori/src/UserSettingsDialogTemplate.tsx
index a2dfa2124a2a2..279a1f92ea71e 100644
--- a/packages/fiori/src/UserSettingsDialogTemplate.tsx
+++ b/packages/fiori/src/UserSettingsDialogTemplate.tsx
@@ -53,7 +53,14 @@ export default function UserSettingsDialogTemplate(this: UserSettingsDialog) {
-
+ {this.saveMode ? (
+ <>
+
+
+ >
+ ) : (
+
+ )}
);
diff --git a/packages/fiori/src/i18n/messagebundle.properties b/packages/fiori/src/i18n/messagebundle.properties
index 908a451d9edf4..2397251013b95 100644
--- a/packages/fiori/src/i18n/messagebundle.properties
+++ b/packages/fiori/src/i18n/messagebundle.properties
@@ -605,6 +605,12 @@ USER_SETTINGS_LIST_ARIA_ROLE_DESC=User settings Item
#XTXT: User settings dialog close button
USER_SETTINGS_DIALOG_CLOSE_BUTTON_TEXT=Close
+#XTXT: User settings dialog save button
+USER_SETTINGS_DIALOG_SAVE_BUTTON_TEXT=Save
+
+#XTXT: User settings dialog cancel button
+USER_SETTINGS_DIALOG_CANCEL_BUTTON_TEXT=Cancel
+
#XTXT: User settings dialog not result text
USER_SETTINGS_DIALOG_NO_SEARCH_RESULTS_TEXT=No search results
diff --git a/packages/fiori/test/pages/UserSettingsDialog.html b/packages/fiori/test/pages/UserSettingsDialog.html
index 828ab5be1944b..8a8f0a7ee375c 100644
--- a/packages/fiori/test/pages/UserSettingsDialog.html
+++ b/packages/fiori/test/pages/UserSettingsDialog.html
@@ -79,6 +79,7 @@
User settings
+User settings (Save mode)
@@ -507,6 +508,117 @@
+
+
+
+
+
+
+
+
+ Reset your personalization settings for the launchpad (such as theme, language, user activities, and home page content).
+
+
+
+
+
+
+
+
+
+
+ Increases the size and spacing of controls to allow you to interact with them more easily using your fingertip.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Display Language:
+
+
+
+
+
+
+
+ Region:
+
+
+
+
+
+ Date Format:
+
+
+
+
+
+ Time Format:
+
+
+
+
+
+
+
+
+
+
+ Reset Personalization content
+
+
+ Reset All Settings content
+
+
+
+
+
+
+ Do you want to save your changes and close the dialog?
+
+
+
+
+
+
+
+ Changing the display language to [New Language] will update the language across the user interface.
+
+
+
+
+
+
+
+