diff --git a/Samples-Typescript/DashboardLayout/DashboardLayout.trex b/Samples-Typescript/DashboardLayout/DashboardLayout.trex new file mode 100644 index 00000000..39b11050 --- /dev/null +++ b/Samples-Typescript/DashboardLayout/DashboardLayout.trex @@ -0,0 +1,19 @@ + + + + en_US + + Dashboard Layout Sample + + 1.7 + + http://localhost:8765/Samples-Typescript/DashboardLayout/dashboardLayout.html + + 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 + + + + Dashboard Layout Sample + + + diff --git a/Samples-Typescript/DashboardLayout/dashboardLayout.html b/Samples-Typescript/DashboardLayout/dashboardLayout.html new file mode 100644 index 00000000..c2253baa --- /dev/null +++ b/Samples-Typescript/DashboardLayout/dashboardLayout.html @@ -0,0 +1,28 @@ + + + + Dashboard Layout Sample + + + + + + + + + + + + + + +
+

Dashboard Layout Sample

+ +
+

Dashboard Changes

+
+
+
+ + diff --git a/Samples-Typescript/DashboardLayout/dashboardLayout.ts b/Samples-Typescript/DashboardLayout/dashboardLayout.ts new file mode 100644 index 00000000..29e6fbe9 --- /dev/null +++ b/Samples-Typescript/DashboardLayout/dashboardLayout.ts @@ -0,0 +1,154 @@ +import { DashboardLayoutChange, DashboardLayoutChangedEvent, DashboardObject, TableauEvent } from '@tableau/extensions-api-types'; + +// Wrap everything in an anonymous function to avoid polluting the global namespace +(async () => { + class DashboardLayout { + public dashboardObjects: DashboardObject[]; + private self: DashboardLayout; + + // Avoid globals. + constructor(private _$: JQueryStatic) {} + + /** + * Initializes the extension + */ + public async initialize() { + console.log('Waiting for DOM ready'); + await this._$.ready; + console.log('Initializing extension API'); + await tableau.extensions.initializeAsync(); + + const dashboard = tableau.extensions.dashboardContent.dashboard; + this.dashboardObjects = dashboard.objects; + console.log(this.dashboardObjects); + + // enabling dashboard event button + this._$('#dashboard-event-btn').prop('disabled', false); + this._$('#dashboard-event-btn').click(this.onEventButtonClick.bind(this)); + } + + // When changes are made to the dashboard we get all the details for each of the + // dashboard objects that were changed and compare it with their previous values. + // The dashboardLayoutChangeDetails property is a map of dashboard obj3ct ids to + // an array of dashboard layout changes. + // Dashboard layout change events are invoked when dashboard objects are resized, + // repositioned, added, and more. See DashboardLayoutChange in the API documentation + // for all possible actions. + // Extension reloads when worksheets are added / removed. + private onDashboardLayoutChange(event: TableauEvent) { + console.log(event); + const dashboardEvent = event as DashboardLayoutChangedEvent; + const dashboardEventDetails = dashboardEvent.dashboardLayoutChangeDetails; + const dashboard = tableau.extensions.dashboardContent.dashboard; + + // updating dashboard objects and storing the previous dashboard objects for referrence. + const oldDashboardObjects = this.dashboardObjects; + this.dashboardObjects = dashboard.objects; + + // An empty dashboard layout change event may be invoked when loading an extension from the manifest. + // In this case we ignore it and return. + if (dashboardEventDetails === undefined || dashboardEventDetails.size === 0) { + return; + } + + // Emptying previous content from the UI's change list. + this._$('#dashboard-layout-change-list').empty(); + + // Updating UI's change list to display information on the current dashboard event. + dashboardEventDetails.forEach((changesMade: DashboardLayoutChange[], dashboardObjectId: number) => { + // getting dashboard object from its id + const dashboardObject = dashboard.getDashboardObjectById(dashboardObjectId); + + // building a div for the changes made to this dashboard object. + const changesDiv = this._$('
'); + + // checking if this dashboard object was added as part of the event. + if (changesMade.includes(tableau.DashboardLayoutChange.Added)) { + const toAppend = this._$('
'); + toAppend.text(`Dashboard Object ${dashboardObjectId} added: "${dashboardObject.name}"`); + changesDiv.append(toAppend); + this._$('#dashboard-layout-change-list').append(changesDiv); + return; + } + + // getting old dashboard object before event to compare it with the current one. + const oldDashboardObject = oldDashboardObjects.find(o => o.id === dashboardObjectId); + + // checking if this dashboard object was removed as part of the event. + if (changesMade.includes(tableau.DashboardLayoutChange.Removed)) { + const toAppend = this._$('
'); + toAppend.text(`Dashboard Object ${dashboardObjectId} removed: "${oldDashboardObject.name}"`); + changesDiv.append(toAppend); + this._$('#dashboard-layout-change-list').append(changesDiv); + return; + } + + // the following dashboard changes are not mutually exclusive, so we list them together. + const h6 = this._$('
'); + h6.text(`Dashboard Object ${dashboardObjectId}: "${dashboardObject.name}"`); + changesDiv.append(h6); + const ul = this._$('