+ To see the Workspace API examples in action, you'll need to open the
+ "LWC Recipes Console App". If you are already there, open the
+ Workspace API examples on a tab by clicking on this button.
+
+
+
+
+
+
diff --git a/force-app/main/default/lwc/workspaceAPI/workspaceAPI.js b/force-app/main/default/lwc/workspaceAPI/workspaceAPI.js
new file mode 100644
index 000000000..e1f947cdb
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPI/workspaceAPI.js
@@ -0,0 +1,16 @@
+import { LightningElement, wire } from 'lwc';
+import { NavigationMixin } from 'lightning/navigation';
+import getSingleContact from '@salesforce/apex/ContactController.getSingleContact';
+
+export default class Lds extends NavigationMixin(LightningElement) {
+ @wire(getSingleContact) contact;
+
+ navigateToWorkspaceAPIExamples() {
+ this[NavigationMixin.Navigate]({
+ type: 'standard__navItemPage',
+ attributes: {
+ apiName: 'Workspace_API'
+ }
+ });
+ }
+}
diff --git a/force-app/main/default/lwc/workspaceAPI/workspaceAPI.js-meta.xml b/force-app/main/default/lwc/workspaceAPI/workspaceAPI.js-meta.xml
new file mode 100644
index 000000000..b67524848
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPI/workspaceAPI.js-meta.xml
@@ -0,0 +1,10 @@
+
+
+ 59.0
+ true
+
+ lightning__AppPage
+ lightning__RecordPage
+ lightning__HomePage
+
+
diff --git a/force-app/main/default/lwc/workspaceAPICloseTab/__tests__/workspaceAPICloseTab.test.js b/force-app/main/default/lwc/workspaceAPICloseTab/__tests__/workspaceAPICloseTab.test.js
new file mode 100644
index 000000000..c92f3e3f9
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPICloseTab/__tests__/workspaceAPICloseTab.test.js
@@ -0,0 +1,54 @@
+import { createElement } from 'lwc';
+import {
+ IsConsoleNavigation,
+ getFocusedTabInfo,
+ closeTab,
+ FOCUSED_TAB
+} from 'lightning/platformWorkspaceApi';
+import WorkspaceAPICloseTab from 'c/workspaceAPICloseTab';
+
+describe('c-workspace-api-close-tab', () => {
+ afterEach(() => {
+ // The jsdom instance is shared across test cases in a single file so reset the DOM
+ while (document.body.firstChild) {
+ document.body.removeChild(document.body.firstChild);
+ }
+ });
+
+ // Helper function to wait until the microtask queue is empty. This is needed for promise
+ // timing when calling async functions
+ async function flushPromises() {
+ return Promise.resolve();
+ }
+
+ it('Calls the related platformWorkspaceApi methods', async () => {
+ // Create component
+ const element = createElement('c-workspace-api-close-tab', {
+ is: WorkspaceAPICloseTab
+ });
+ document.body.appendChild(element);
+
+ IsConsoleNavigation.emit(true);
+
+ // Query lightning-button component element
+ const buttonEl = element.shadowRoot.querySelector('lightning-button');
+ buttonEl.click();
+
+ await flushPromises();
+
+ // Compare if related platformWorkspaceApi functions have been called
+ expect(getFocusedTabInfo).toHaveBeenCalled();
+ expect(closeTab).toHaveBeenCalledWith(FOCUSED_TAB);
+ });
+
+ it('is accessible', async () => {
+ // Create component
+ const element = createElement('c-workspace-api-close-tab', {
+ is: WorkspaceAPICloseTab
+ });
+ document.body.appendChild(element);
+
+ // Check accessibility
+ await expect(element).toBeAccessible();
+ });
+});
diff --git a/force-app/main/default/lwc/workspaceAPICloseTab/workspaceAPICloseTab.html b/force-app/main/default/lwc/workspaceAPICloseTab/workspaceAPICloseTab.html
new file mode 100644
index 000000000..c25fb977c
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPICloseTab/workspaceAPICloseTab.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ Close a tab.
+
+
+
diff --git a/force-app/main/default/lwc/workspaceAPICloseTab/workspaceAPICloseTab.js b/force-app/main/default/lwc/workspaceAPICloseTab/workspaceAPICloseTab.js
new file mode 100644
index 000000000..92c74514d
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPICloseTab/workspaceAPICloseTab.js
@@ -0,0 +1,18 @@
+import { LightningElement, wire } from 'lwc';
+import {
+ closeTab,
+ IsConsoleNavigation,
+ getFocusedTabInfo
+} from 'lightning/platformWorkspaceApi';
+
+export default class WorkspaceAPICloseTab extends LightningElement {
+ @wire(IsConsoleNavigation) isConsoleNavigation;
+
+ async closeTab() {
+ if (!this.isConsoleNavigation) {
+ return;
+ }
+ const { tabId } = await getFocusedTabInfo();
+ await closeTab(tabId);
+ }
+}
diff --git a/force-app/main/default/lwc/workspaceAPICloseTab/workspaceAPICloseTab.js-meta.xml b/force-app/main/default/lwc/workspaceAPICloseTab/workspaceAPICloseTab.js-meta.xml
new file mode 100644
index 000000000..7918bdb82
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPICloseTab/workspaceAPICloseTab.js-meta.xml
@@ -0,0 +1,8 @@
+
+
+ 60.0
+ true
+
+ lightning__UtilityBar
+
+
diff --git a/force-app/main/default/lwc/workspaceAPIDisableTabClose/__tests__/workspaceAPIDisableTabClose.test.js b/force-app/main/default/lwc/workspaceAPIDisableTabClose/__tests__/workspaceAPIDisableTabClose.test.js
new file mode 100644
index 000000000..f0cc39b7f
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPIDisableTabClose/__tests__/workspaceAPIDisableTabClose.test.js
@@ -0,0 +1,58 @@
+import { createElement } from 'lwc';
+import {
+ disableTabClose,
+ IsConsoleNavigation,
+ getFocusedTabInfo,
+ FOCUSED_TAB
+} from 'lightning/platformWorkspaceApi';
+
+import WorkspaceAPIDisableTabClose from 'c/workspaceAPIDisableTabClose';
+
+describe('c-workspace-api-disable-tab-close', () => {
+ afterEach(() => {
+ // The jsdom instance is shared across test cases in a single file so reset the DOM
+ while (document.body.firstChild) {
+ document.body.removeChild(document.body.firstChild);
+ }
+ });
+
+ // Helper function to wait until the microtask queue is empty. This is needed for promise
+ // timing when calling async functions
+ async function flushPromises() {
+ return Promise.resolve();
+ }
+
+ it('Calls the related platformWorkspaceApi methods', async () => {
+ // Create component
+ const element = createElement('c-workspace-api-disable-tab-close', {
+ is: WorkspaceAPIDisableTabClose
+ });
+ document.body.appendChild(element);
+
+ IsConsoleNavigation.emit(true);
+
+ // Query lightning-input component element
+ const inputEl = element.shadowRoot.querySelector('lightning-input');
+ const toggleValue = true;
+ inputEl.dispatchEvent(
+ new CustomEvent('change', { detail: { checked: toggleValue } })
+ );
+
+ await flushPromises();
+
+ // Compare if related platformWorkspaceApi functions have been called
+ expect(getFocusedTabInfo).toHaveBeenCalled();
+ expect(disableTabClose).toHaveBeenCalledWith(FOCUSED_TAB, toggleValue);
+ });
+
+ it('is accessible', async () => {
+ // Create component
+ const element = createElement('c-workspace-api-disable-tab-close', {
+ is: WorkspaceAPIDisableTabClose
+ });
+ document.body.appendChild(element);
+
+ // Check accessibility
+ await expect(element).toBeAccessible();
+ });
+});
diff --git a/force-app/main/default/lwc/workspaceAPIDisableTabClose/workspaceAPIDisableTabClose.html b/force-app/main/default/lwc/workspaceAPIDisableTabClose/workspaceAPIDisableTabClose.html
new file mode 100644
index 000000000..8a803de4d
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPIDisableTabClose/workspaceAPIDisableTabClose.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+ Disable close button on a tab.
+
+
+
diff --git a/force-app/main/default/lwc/workspaceAPIDisableTabClose/workspaceAPIDisableTabClose.js b/force-app/main/default/lwc/workspaceAPIDisableTabClose/workspaceAPIDisableTabClose.js
new file mode 100644
index 000000000..4a85fb332
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPIDisableTabClose/workspaceAPIDisableTabClose.js
@@ -0,0 +1,19 @@
+import { LightningElement, wire } from 'lwc';
+import {
+ disableTabClose,
+ IsConsoleNavigation,
+ getFocusedTabInfo
+} from 'lightning/platformWorkspaceApi';
+
+export default class WorkspaceAPIDisableTabClose extends LightningElement {
+ @wire(IsConsoleNavigation) isConsoleNavigation;
+
+ async disableTabClose(event) {
+ if (!this.isConsoleNavigation) {
+ return;
+ }
+ const close = event.detail.checked;
+ const { tabId } = await getFocusedTabInfo();
+ await disableTabClose(tabId, close);
+ }
+}
diff --git a/force-app/main/default/lwc/workspaceAPIDisableTabClose/workspaceAPIDisableTabClose.js-meta.xml b/force-app/main/default/lwc/workspaceAPIDisableTabClose/workspaceAPIDisableTabClose.js-meta.xml
new file mode 100644
index 000000000..075c6d873
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPIDisableTabClose/workspaceAPIDisableTabClose.js-meta.xml
@@ -0,0 +1,8 @@
+
+
+ 60.0
+ true
+
+ lightning__AppPage
+
+
diff --git a/force-app/main/default/lwc/workspaceAPIFocusTab/__tests__/workspaceAPIFocusTab.test.js b/force-app/main/default/lwc/workspaceAPIFocusTab/__tests__/workspaceAPIFocusTab.test.js
new file mode 100644
index 000000000..1e7b670c4
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPIFocusTab/__tests__/workspaceAPIFocusTab.test.js
@@ -0,0 +1,61 @@
+import { createElement } from 'lwc';
+import {
+ focusTab,
+ IsConsoleNavigation,
+ getFocusedTabInfo,
+ getAllTabInfo,
+ FOCUSED_TAB
+} from 'lightning/platformWorkspaceApi';
+import WorkspaceAPIFocusTab from 'c/workspaceAPIFocusTab';
+
+describe('c-workspace-api-focus-tab', () => {
+ afterEach(() => {
+ // The jsdom instance is shared across test cases in a single file so reset the DOM
+ while (document.body.firstChild) {
+ document.body.removeChild(document.body.firstChild);
+ }
+ });
+
+ // Helper function to wait until the microtask queue is empty. This is needed for promise
+ // timing when calling async functions
+ async function flushPromises() {
+ return Promise.resolve();
+ }
+
+ it('Calls the related platformWorkspaceApi methods', async () => {
+ // Create component
+ const element = createElement('c-workspace-api-focus-tab', {
+ is: WorkspaceAPIFocusTab
+ });
+ document.body.appendChild(element);
+
+ IsConsoleNavigation.emit(true);
+
+ // Query lightning-button component element
+ const buttonEl = element.shadowRoot.querySelector('lightning-button');
+ buttonEl.click();
+
+ await flushPromises();
+
+ // Compare if related platformWorkspaceApi functions have been called
+ expect(getFocusedTabInfo).toHaveBeenCalled();
+ expect(getAllTabInfo).toHaveBeenCalled();
+ const allTabs = await getAllTabInfo();
+ const selectedTabIndex = allTabs.findIndex(
+ (possibleNextTab) => possibleNextTab.tabId === FOCUSED_TAB
+ );
+ const nextTabId = allTabs[selectedTabIndex + 1].tabId;
+ expect(focusTab).toHaveBeenCalledWith(nextTabId);
+ });
+
+ it('is accessible', async () => {
+ // Create component
+ const element = createElement('c-workspace-api-focus-tab', {
+ is: WorkspaceAPIFocusTab
+ });
+ document.body.appendChild(element);
+
+ // Check accessibility
+ await expect(element).toBeAccessible();
+ });
+});
diff --git a/force-app/main/default/lwc/workspaceAPIFocusTab/workspaceAPIFocusTab.html b/force-app/main/default/lwc/workspaceAPIFocusTab/workspaceAPIFocusTab.html
new file mode 100644
index 000000000..e7d16de8b
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPIFocusTab/workspaceAPIFocusTab.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ Focus on next open tab.
+
+
+
diff --git a/force-app/main/default/lwc/workspaceAPIFocusTab/workspaceAPIFocusTab.js b/force-app/main/default/lwc/workspaceAPIFocusTab/workspaceAPIFocusTab.js
new file mode 100644
index 000000000..7edf31c33
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPIFocusTab/workspaceAPIFocusTab.js
@@ -0,0 +1,25 @@
+import { LightningElement, wire } from 'lwc';
+import {
+ focusTab,
+ IsConsoleNavigation,
+ getFocusedTabInfo,
+ getAllTabInfo
+} from 'lightning/platformWorkspaceApi';
+
+export default class WorkspaceAPIFocusTab extends LightningElement {
+ @wire(IsConsoleNavigation) isConsoleNavigation;
+
+ async focusNextTab() {
+ if (!this.isConsoleNavigation) {
+ return;
+ }
+ const { tabId } = await getFocusedTabInfo();
+ const allTabs = await getAllTabInfo();
+ const selectedTabIndex = allTabs.findIndex(
+ (possibleNextTab) => possibleNextTab.tabId === tabId
+ );
+ const nextTabId = allTabs[selectedTabIndex + 1].tabId;
+
+ await focusTab(nextTabId);
+ }
+}
diff --git a/force-app/main/default/lwc/workspaceAPIFocusTab/workspaceAPIFocusTab.js-meta.xml b/force-app/main/default/lwc/workspaceAPIFocusTab/workspaceAPIFocusTab.js-meta.xml
new file mode 100644
index 000000000..075c6d873
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPIFocusTab/workspaceAPIFocusTab.js-meta.xml
@@ -0,0 +1,8 @@
+
+
+ 60.0
+ true
+
+ lightning__AppPage
+
+
diff --git a/force-app/main/default/lwc/workspaceAPIHighlightTab/__tests__/workspaceAPIHighlightTab.test.js b/force-app/main/default/lwc/workspaceAPIHighlightTab/__tests__/workspaceAPIHighlightTab.test.js
new file mode 100644
index 000000000..ae99b66a7
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPIHighlightTab/__tests__/workspaceAPIHighlightTab.test.js
@@ -0,0 +1,59 @@
+import { createElement } from 'lwc';
+import WorkspaceAPIHighlightTab from 'c/workspaceAPIHighlightTab';
+import {
+ IsConsoleNavigation,
+ getFocusedTabInfo,
+ setTabHighlighted,
+ FOCUSED_TAB
+} from 'lightning/platformWorkspaceApi';
+
+describe('c-workspace-api-highlight-tab', () => {
+ afterEach(() => {
+ // The jsdom instance is shared across test cases in a single file so reset the DOM
+ while (document.body.firstChild) {
+ document.body.removeChild(document.body.firstChild);
+ }
+ });
+
+ // Helper function to wait until the microtask queue is empty. This is needed for promise
+ // timing when calling async functions
+ async function flushPromises() {
+ return Promise.resolve();
+ }
+
+ it('Calls the related platformWorkspaceApi methods', async () => {
+ // Create component
+ const element = createElement('c-workspace-api-highlight-tab', {
+ is: WorkspaceAPIHighlightTab
+ });
+ document.body.appendChild(element);
+
+ IsConsoleNavigation.emit(true);
+
+ // Query lightning-input component element
+ const inputEl = element.shadowRoot.querySelector('lightning-input');
+ inputEl.dispatchEvent(
+ new CustomEvent('change', { detail: { checked: true } })
+ );
+
+ await flushPromises();
+
+ // Compare if related platformWorkspaceApi functions have been called
+ expect(getFocusedTabInfo).toHaveBeenCalled();
+ expect(setTabHighlighted).toHaveBeenCalledWith(FOCUSED_TAB, true, {
+ pulse: true,
+ state: 'success'
+ });
+ });
+
+ it('is accessible', async () => {
+ // Create component
+ const element = createElement('c-workspace-api-highlight-tab', {
+ is: WorkspaceAPIHighlightTab
+ });
+ document.body.appendChild(element);
+
+ // Check accessibility
+ await expect(element).toBeAccessible();
+ });
+});
diff --git a/force-app/main/default/lwc/workspaceAPIHighlightTab/workspaceAPIHighlightTab.html b/force-app/main/default/lwc/workspaceAPIHighlightTab/workspaceAPIHighlightTab.html
new file mode 100644
index 000000000..2307bae35
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPIHighlightTab/workspaceAPIHighlightTab.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+ Highlight focused tab.
+
+
+
diff --git a/force-app/main/default/lwc/workspaceAPIHighlightTab/workspaceAPIHighlightTab.js b/force-app/main/default/lwc/workspaceAPIHighlightTab/workspaceAPIHighlightTab.js
new file mode 100644
index 000000000..6b57d2c3c
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPIHighlightTab/workspaceAPIHighlightTab.js
@@ -0,0 +1,22 @@
+import { LightningElement, wire } from 'lwc';
+import {
+ IsConsoleNavigation,
+ getFocusedTabInfo,
+ setTabHighlighted
+} from 'lightning/platformWorkspaceApi';
+
+export default class WorkspaceAPIHighlightTab extends LightningElement {
+ @wire(IsConsoleNavigation) isConsoleNavigation;
+
+ async highlightTab(event) {
+ if (!this.isConsoleNavigation) {
+ return;
+ }
+ const highlighted = event.detail.checked;
+ const { tabId } = await getFocusedTabInfo();
+ setTabHighlighted(tabId, highlighted, {
+ pulse: true,
+ state: 'success'
+ });
+ }
+}
diff --git a/force-app/main/default/lwc/workspaceAPIHighlightTab/workspaceAPIHighlightTab.js-meta.xml b/force-app/main/default/lwc/workspaceAPIHighlightTab/workspaceAPIHighlightTab.js-meta.xml
new file mode 100644
index 000000000..075c6d873
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPIHighlightTab/workspaceAPIHighlightTab.js-meta.xml
@@ -0,0 +1,8 @@
+
+
+ 60.0
+ true
+
+ lightning__AppPage
+
+
diff --git a/force-app/main/default/lwc/workspaceAPIOpenSubtab/__tests__/workspaceAPIOpenSubtab.test.js b/force-app/main/default/lwc/workspaceAPIOpenSubtab/__tests__/workspaceAPIOpenSubtab.test.js
new file mode 100644
index 000000000..303cbfaaa
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPIOpenSubtab/__tests__/workspaceAPIOpenSubtab.test.js
@@ -0,0 +1,63 @@
+import { createElement } from 'lwc';
+import WorkspaceAPIOpenSubtab from 'c/workspaceAPIOpenSubtab';
+import {
+ IsConsoleNavigation,
+ EnclosingTabId,
+ openSubtab,
+ ENCLOSING_TAB_ID
+} from 'lightning/platformWorkspaceApi';
+
+describe('c-workspace-api-open-subtab', () => {
+ afterEach(() => {
+ // The jsdom instance is shared across test cases in a single file so reset the DOM
+ while (document.body.firstChild) {
+ document.body.removeChild(document.body.firstChild);
+ }
+ });
+
+ // Helper function to wait until the microtask queue is empty. This is needed for promise
+ // timing when calling async functions
+ async function flushPromises() {
+ return Promise.resolve();
+ }
+
+ it('Calls the related platformWorkspaceApi methods', async () => {
+ // Create component
+ const element = createElement('c-workspace-api-open-subtab', {
+ is: WorkspaceAPIOpenSubtab
+ });
+ document.body.appendChild(element);
+
+ const enclosingTabId = 'tab0';
+ IsConsoleNavigation.emit(true);
+ EnclosingTabId.emit(enclosingTabId);
+
+ // Query lightning-button component element
+ const buttonEl = element.shadowRoot.querySelector('lightning-button');
+ buttonEl.click();
+
+ await flushPromises();
+
+ // Compare if related platformWorkspaceApi functions have been called
+ expect(openSubtab).toHaveBeenCalledWith(ENCLOSING_TAB_ID, {
+ pageReference: {
+ type: 'standard__objectPage',
+ attributes: {
+ objectApiName: 'Account',
+ actionName: 'list'
+ }
+ }
+ });
+ });
+
+ it('is accessible', async () => {
+ // Create component
+ const element = createElement('c-workspace-api-open-subtab', {
+ is: WorkspaceAPIOpenSubtab
+ });
+ document.body.appendChild(element);
+
+ // Check accessibility
+ await expect(element).toBeAccessible();
+ });
+});
diff --git a/force-app/main/default/lwc/workspaceAPIOpenSubtab/workspaceAPIOpenSubtab.html b/force-app/main/default/lwc/workspaceAPIOpenSubtab/workspaceAPIOpenSubtab.html
new file mode 100644
index 000000000..2b0562d50
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPIOpenSubtab/workspaceAPIOpenSubtab.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+ Find enclosing tab and add a subtab to it.
+
+
+
diff --git a/force-app/main/default/lwc/workspaceAPIOpenSubtab/workspaceAPIOpenSubtab.js b/force-app/main/default/lwc/workspaceAPIOpenSubtab/workspaceAPIOpenSubtab.js
new file mode 100644
index 000000000..a86272251
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPIOpenSubtab/workspaceAPIOpenSubtab.js
@@ -0,0 +1,26 @@
+import { LightningElement, wire } from 'lwc';
+import {
+ IsConsoleNavigation,
+ EnclosingTabId,
+ openSubtab
+} from 'lightning/platformWorkspaceApi';
+
+export default class WorkspaceAPIOpenSubtab extends LightningElement {
+ @wire(IsConsoleNavigation) isConsoleNavigation;
+ @wire(EnclosingTabId) enclosingTabId;
+
+ findEnclosingTabAndOpenSubtab() {
+ if (!this.isConsoleNavigation || !this.enclosingTabId) {
+ return;
+ }
+ openSubtab(this.enclosingTabId, {
+ pageReference: {
+ type: 'standard__objectPage',
+ attributes: {
+ objectApiName: 'Account',
+ actionName: 'list'
+ }
+ }
+ });
+ }
+}
diff --git a/force-app/main/default/lwc/workspaceAPIOpenSubtab/workspaceAPIOpenSubtab.js-meta.xml b/force-app/main/default/lwc/workspaceAPIOpenSubtab/workspaceAPIOpenSubtab.js-meta.xml
new file mode 100644
index 000000000..075c6d873
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPIOpenSubtab/workspaceAPIOpenSubtab.js-meta.xml
@@ -0,0 +1,8 @@
+
+
+ 60.0
+ true
+
+ lightning__AppPage
+
+
diff --git a/force-app/main/default/lwc/workspaceAPIOpenTab/__tests__/workspaceAPIOpenTab.test.js b/force-app/main/default/lwc/workspaceAPIOpenTab/__tests__/workspaceAPIOpenTab.test.js
new file mode 100644
index 000000000..c5cb48307
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPIOpenTab/__tests__/workspaceAPIOpenTab.test.js
@@ -0,0 +1,58 @@
+import { createElement } from 'lwc';
+import WorkspaceAPIOpenTab from 'c/workspaceAPIOpenTab';
+import { IsConsoleNavigation, openTab } from 'lightning/platformWorkspaceApi';
+
+describe('c-workspace-api-open-tab', () => {
+ afterEach(() => {
+ // The jsdom instance is shared across test cases in a single file so reset the DOM
+ while (document.body.firstChild) {
+ document.body.removeChild(document.body.firstChild);
+ }
+ });
+
+ // Helper function to wait until the microtask queue is empty. This is needed for promise
+ // timing when calling async functions
+ async function flushPromises() {
+ return Promise.resolve();
+ }
+
+ it('Calls the related platformWorkspaceApi methods', async () => {
+ // Create component
+ const element = createElement('c-workspace-api-open-tab', {
+ is: WorkspaceAPIOpenTab
+ });
+ document.body.appendChild(element);
+
+ IsConsoleNavigation.emit(true);
+
+ // Query lightning-button component element
+ const buttonEl = element.shadowRoot.querySelector('lightning-button');
+ buttonEl.click();
+
+ await flushPromises();
+
+ // Compare if related platformWorkspaceApi functions have been called
+ expect(openTab).toHaveBeenCalledWith({
+ pageReference: {
+ type: 'standard__objectPage',
+ attributes: {
+ objectApiName: 'Contact',
+ actionName: 'list'
+ }
+ },
+ focus: true,
+ label: 'Contacts List'
+ });
+ });
+
+ it('is accessible', async () => {
+ // Create component
+ const element = createElement('c-workspace-api-open-tab', {
+ is: WorkspaceAPIOpenTab
+ });
+ document.body.appendChild(element);
+
+ // Check accessibility
+ await expect(element).toBeAccessible();
+ });
+});
diff --git a/force-app/main/default/lwc/workspaceAPIOpenTab/workspaceAPIOpenTab.html b/force-app/main/default/lwc/workspaceAPIOpenTab/workspaceAPIOpenTab.html
new file mode 100644
index 000000000..b3cd03cd9
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPIOpenTab/workspaceAPIOpenTab.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ Open a tab indicating a page reference.
+
+
+
diff --git a/force-app/main/default/lwc/workspaceAPIOpenTab/workspaceAPIOpenTab.js b/force-app/main/default/lwc/workspaceAPIOpenTab/workspaceAPIOpenTab.js
new file mode 100644
index 000000000..7947281cc
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPIOpenTab/workspaceAPIOpenTab.js
@@ -0,0 +1,23 @@
+import { LightningElement, wire } from 'lwc';
+import { IsConsoleNavigation, openTab } from 'lightning/platformWorkspaceApi';
+
+export default class WorkspaceAPIOpenTab extends LightningElement {
+ @wire(IsConsoleNavigation) isConsoleNavigation;
+
+ async openTab() {
+ if (!this.isConsoleNavigation) {
+ return;
+ }
+ await openTab({
+ pageReference: {
+ type: 'standard__objectPage',
+ attributes: {
+ objectApiName: 'Contact',
+ actionName: 'list'
+ }
+ },
+ focus: true,
+ label: 'Contacts List'
+ });
+ }
+}
diff --git a/force-app/main/default/lwc/workspaceAPIOpenTab/workspaceAPIOpenTab.js-meta.xml b/force-app/main/default/lwc/workspaceAPIOpenTab/workspaceAPIOpenTab.js-meta.xml
new file mode 100644
index 000000000..075c6d873
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPIOpenTab/workspaceAPIOpenTab.js-meta.xml
@@ -0,0 +1,8 @@
+
+
+ 60.0
+ true
+
+ lightning__AppPage
+
+
diff --git a/force-app/main/default/lwc/workspaceAPIRefreshTab/__tests__/workspaceAPIRefreshTab.test.js b/force-app/main/default/lwc/workspaceAPIRefreshTab/__tests__/workspaceAPIRefreshTab.test.js
new file mode 100644
index 000000000..f74a49bd2
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPIRefreshTab/__tests__/workspaceAPIRefreshTab.test.js
@@ -0,0 +1,56 @@
+import { createElement } from 'lwc';
+import {
+ IsConsoleNavigation,
+ getFocusedTabInfo,
+ refreshTab,
+ FOCUSED_TAB
+} from 'lightning/platformWorkspaceApi';
+import WorkspaceAPIRefreshTab from 'c/workspaceAPIRefreshTab';
+
+describe('c-workspace-api-refresh-tab', () => {
+ afterEach(() => {
+ // The jsdom instance is shared across test cases in a single file so reset the DOM
+ while (document.body.firstChild) {
+ document.body.removeChild(document.body.firstChild);
+ }
+ });
+
+ // Helper function to wait until the microtask queue is empty. This is needed for promise
+ // timing when calling async functions
+ async function flushPromises() {
+ return Promise.resolve();
+ }
+
+ it('Calls the related platformWorkspaceApi methods', async () => {
+ // Create component
+ const element = createElement('c-workspace-api-refresh-tab', {
+ is: WorkspaceAPIRefreshTab
+ });
+ document.body.appendChild(element);
+
+ IsConsoleNavigation.emit(true);
+
+ // Query lightning-button component element
+ const buttonEl = element.shadowRoot.querySelector('lightning-button');
+ buttonEl.click();
+
+ await flushPromises();
+
+ // Compare if related platformWorkspaceApi functions have been called
+ expect(getFocusedTabInfo).toHaveBeenCalled();
+ expect(refreshTab).toHaveBeenCalledWith(FOCUSED_TAB, {
+ includeAllSubtabs: true
+ });
+ });
+
+ it('is accessible', async () => {
+ // Create component
+ const element = createElement('c-workspace-api-refresh-tab', {
+ is: WorkspaceAPIRefreshTab
+ });
+ document.body.appendChild(element);
+
+ // Check accessibility
+ await expect(element).toBeAccessible();
+ });
+});
diff --git a/force-app/main/default/lwc/workspaceAPIRefreshTab/workspaceAPIRefreshTab.html b/force-app/main/default/lwc/workspaceAPIRefreshTab/workspaceAPIRefreshTab.html
new file mode 100644
index 000000000..b5b21c666
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPIRefreshTab/workspaceAPIRefreshTab.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ Refresh focused tab and its subtabs.
+
+
+
diff --git a/force-app/main/default/lwc/workspaceAPIRefreshTab/workspaceAPIRefreshTab.js b/force-app/main/default/lwc/workspaceAPIRefreshTab/workspaceAPIRefreshTab.js
new file mode 100644
index 000000000..e97f71bae
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPIRefreshTab/workspaceAPIRefreshTab.js
@@ -0,0 +1,20 @@
+import { LightningElement, wire } from 'lwc';
+import {
+ IsConsoleNavigation,
+ getFocusedTabInfo,
+ refreshTab
+} from 'lightning/platformWorkspaceApi';
+
+export default class WorkspaceAPIRefreshTab extends LightningElement {
+ @wire(IsConsoleNavigation) isConsoleNavigation;
+
+ async refreshTab() {
+ if (!this.isConsoleNavigation) {
+ return;
+ }
+ const { tabId } = await getFocusedTabInfo();
+ await refreshTab(tabId, {
+ includeAllSubtabs: true
+ });
+ }
+}
diff --git a/force-app/main/default/lwc/workspaceAPIRefreshTab/workspaceAPIRefreshTab.js-meta.xml b/force-app/main/default/lwc/workspaceAPIRefreshTab/workspaceAPIRefreshTab.js-meta.xml
new file mode 100644
index 000000000..075c6d873
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPIRefreshTab/workspaceAPIRefreshTab.js-meta.xml
@@ -0,0 +1,8 @@
+
+
+ 60.0
+ true
+
+ lightning__AppPage
+
+
diff --git a/force-app/main/default/lwc/workspaceAPISetTabIcon/__tests__/workspaceAPISetTabIcon.test.js b/force-app/main/default/lwc/workspaceAPISetTabIcon/__tests__/workspaceAPISetTabIcon.test.js
new file mode 100644
index 000000000..2b271bb96
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPISetTabIcon/__tests__/workspaceAPISetTabIcon.test.js
@@ -0,0 +1,58 @@
+import { createElement } from 'lwc';
+import WorkspaceAPISetTabIcon from 'c/workspaceAPISetTabIcon';
+import {
+ IsConsoleNavigation,
+ getFocusedTabInfo,
+ setTabIcon,
+ FOCUSED_TAB
+} from 'lightning/platformWorkspaceApi';
+
+describe('c-workspace-api-set-tab-icon', () => {
+ afterEach(() => {
+ // The jsdom instance is shared across test cases in a single file so reset the DOM
+ while (document.body.firstChild) {
+ document.body.removeChild(document.body.firstChild);
+ }
+ });
+
+ // Helper function to wait until the microtask queue is empty. This is needed for promise
+ // timing when calling async functions
+ async function flushPromises() {
+ return Promise.resolve();
+ }
+
+ it('Calls the related platformWorkspaceApi methods', async () => {
+ // Create component
+ const element = createElement('c-workspace-api-set-tab-icon', {
+ is: WorkspaceAPISetTabIcon
+ });
+ document.body.appendChild(element);
+
+ const TAB_ICON = 'utility:animal_and_nature';
+ const TAB_ICON_ALT_TEXT = 'Animal and Nature';
+ IsConsoleNavigation.emit(true);
+
+ // Query lightning-button component element
+ const buttonEl = element.shadowRoot.querySelector('lightning-button');
+ buttonEl.click();
+
+ await flushPromises();
+
+ // Compare if related platformWorkspaceApi functions have been called
+ expect(getFocusedTabInfo).toHaveBeenCalled();
+ expect(setTabIcon).toHaveBeenCalledWith(FOCUSED_TAB, TAB_ICON, {
+ iconAlt: TAB_ICON_ALT_TEXT
+ });
+ });
+
+ it('is accessible', async () => {
+ // Create component
+ const element = createElement('c-workspace-api-set-tab-icon', {
+ is: WorkspaceAPISetTabIcon
+ });
+ document.body.appendChild(element);
+
+ // Check accessibility
+ await expect(element).toBeAccessible();
+ });
+});
diff --git a/force-app/main/default/lwc/workspaceAPISetTabIcon/workspaceAPISetTabIcon.html b/force-app/main/default/lwc/workspaceAPISetTabIcon/workspaceAPISetTabIcon.html
new file mode 100644
index 000000000..0b653d35a
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPISetTabIcon/workspaceAPISetTabIcon.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ Set SLDS icon and its alt text for a tab.
+
+
+
diff --git a/force-app/main/default/lwc/workspaceAPISetTabIcon/workspaceAPISetTabIcon.js b/force-app/main/default/lwc/workspaceAPISetTabIcon/workspaceAPISetTabIcon.js
new file mode 100644
index 000000000..fedd43ae5
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPISetTabIcon/workspaceAPISetTabIcon.js
@@ -0,0 +1,24 @@
+import { LightningElement, wire } from 'lwc';
+import {
+ IsConsoleNavigation,
+ getFocusedTabInfo,
+ setTabIcon
+} from 'lightning/platformWorkspaceApi';
+
+const TAB_ICON = 'utility:animal_and_nature';
+const TAB_ICON_ALT_TEXT = 'Animal and Nature';
+
+export default class WorkspaceAPISetTabIcon extends LightningElement {
+ @wire(IsConsoleNavigation) isConsoleNavigation;
+
+ async setTabIcon() {
+ if (!this.isConsoleNavigation) {
+ return;
+ }
+
+ const { tabId } = await getFocusedTabInfo();
+ setTabIcon(tabId, TAB_ICON, {
+ iconAlt: TAB_ICON_ALT_TEXT
+ });
+ }
+}
diff --git a/force-app/main/default/lwc/workspaceAPISetTabIcon/workspaceAPISetTabIcon.js-meta.xml b/force-app/main/default/lwc/workspaceAPISetTabIcon/workspaceAPISetTabIcon.js-meta.xml
new file mode 100644
index 000000000..075c6d873
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPISetTabIcon/workspaceAPISetTabIcon.js-meta.xml
@@ -0,0 +1,8 @@
+
+
+ 60.0
+ true
+
+ lightning__AppPage
+
+
diff --git a/force-app/main/default/lwc/workspaceAPISetTabLabel/__tests__/workspaceAPISetTabLabel.test.js b/force-app/main/default/lwc/workspaceAPISetTabLabel/__tests__/workspaceAPISetTabLabel.test.js
new file mode 100644
index 000000000..f84d8ddf1
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPISetTabLabel/__tests__/workspaceAPISetTabLabel.test.js
@@ -0,0 +1,55 @@
+import { createElement } from 'lwc';
+import WorkspaceAPISetTabLabel from 'c/workspaceAPISetTabLabel';
+import {
+ IsConsoleNavigation,
+ getFocusedTabInfo,
+ setTabLabel,
+ FOCUSED_TAB
+} from 'lightning/platformWorkspaceApi';
+
+describe('c-workspace-api-set-tab-label', () => {
+ afterEach(() => {
+ // The jsdom instance is shared across test cases in a single file so reset the DOM
+ while (document.body.firstChild) {
+ document.body.removeChild(document.body.firstChild);
+ }
+ });
+
+ // Helper function to wait until the microtask queue is empty. This is needed for promise
+ // timing when calling async functions
+ async function flushPromises() {
+ return Promise.resolve();
+ }
+
+ it('Calls the related platformWorkspaceApi methods', async () => {
+ // Create component
+ const element = createElement('c-workspace-api-set-tab-label', {
+ is: WorkspaceAPISetTabLabel
+ });
+ document.body.appendChild(element);
+
+ const TAB_LABEL = 'Awesome Label';
+ IsConsoleNavigation.emit(true);
+
+ // Query lightning-button component element
+ const buttonEl = element.shadowRoot.querySelector('lightning-button');
+ buttonEl.click();
+
+ await flushPromises();
+
+ // Compare if related platformWorkspaceApi functions have been called
+ expect(getFocusedTabInfo).toHaveBeenCalled();
+ expect(setTabLabel).toHaveBeenCalledWith(FOCUSED_TAB, TAB_LABEL);
+ });
+
+ it('is accessible', async () => {
+ // Create component
+ const element = createElement('c-workspace-api-set-tab-label', {
+ is: WorkspaceAPISetTabLabel
+ });
+ document.body.appendChild(element);
+
+ // Check accessibility
+ await expect(element).toBeAccessible();
+ });
+});
diff --git a/force-app/main/default/lwc/workspaceAPISetTabLabel/workspaceAPISetTabLabel.html b/force-app/main/default/lwc/workspaceAPISetTabLabel/workspaceAPISetTabLabel.html
new file mode 100644
index 000000000..a731b776e
--- /dev/null
+++ b/force-app/main/default/lwc/workspaceAPISetTabLabel/workspaceAPISetTabLabel.html
@@ -0,0 +1,17 @@
+
+
+