Skip to content

Commit cada28c

Browse files
authored
Merge pull request #422 from tableau/dev
Release version 1.7
2 parents b165c8e + 7f89ae5 commit cada28c

File tree

92 files changed

+22684
-1850
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+22684
-1850
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,6 @@ npm-debug.log
99
dist/
1010

1111
.DS_Store
12+
13+
# ignore local npmrc files
14+
.npmrc
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest manifest-version="0.1" xmlns="http://www.tableau.com/xml/extension_manifest">
3+
<dashboard-extension id="com.tableau.extensions.samples.dashboardlayout" extension-version="0.1.0">
4+
<default-locale>en_US</default-locale>
5+
<name resource-id="name"/>
6+
<description>Dashboard Layout Sample</description>
7+
<author name="tableau" email="[email protected]" organization="tableau" website="https://www.tableau.com"/>
8+
<min-api-version>1.7</min-api-version>
9+
<source-location>
10+
<url>http://localhost:8765/Samples-Typescript/DashboardLayout/dashboardLayout.html</url>
11+
</source-location>
12+
<icon>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</icon>
13+
</dashboard-extension>
14+
<resources>
15+
<resource id="name">
16+
<text locale="en_US">Dashboard Layout Sample</text>
17+
</resource>
18+
</resources>
19+
</manifest>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<title>Dashboard Layout Sample</title>
5+
<!-- jQuery -->
6+
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
7+
8+
<!-- Bootstrap -->
9+
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
10+
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
11+
12+
<!-- Extensions Library (this will be hosted on a CDN eventually) -->
13+
<script src="../../lib/tableau.extensions.1.latest.js"></script>
14+
15+
<!-- Our extension's code -->
16+
<script src="../../dist/dashboardLayout.js"></script>
17+
</head>
18+
<body>
19+
<div class="container">
20+
<h1>Dashboard Layout Sample</h1>
21+
<button id="dashboard-event-btn" class="btn btn-primary" disabled="true">Add Dashboard Event</button>
22+
<hr>
23+
<h3>Dashboard Changes</h3>
24+
<div id="dashboard-layout-change-list" class="container">
25+
</div>
26+
</div>
27+
</body>
28+
</html>
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
import { DashboardLayoutChange, DashboardLayoutChangedEvent, DashboardObject, TableauEvent } from '@tableau/extensions-api-types';
2+
3+
// Wrap everything in an anonymous function to avoid polluting the global namespace
4+
(async () => {
5+
class DashboardLayout {
6+
public dashboardObjects: DashboardObject[];
7+
private self: DashboardLayout;
8+
9+
// Avoid globals.
10+
constructor(private _$: JQueryStatic) {}
11+
12+
/**
13+
* Initializes the extension
14+
*/
15+
public async initialize() {
16+
console.log('Waiting for DOM ready');
17+
await this._$.ready;
18+
console.log('Initializing extension API');
19+
await tableau.extensions.initializeAsync();
20+
21+
const dashboard = tableau.extensions.dashboardContent.dashboard;
22+
this.dashboardObjects = dashboard.objects;
23+
console.log(this.dashboardObjects);
24+
25+
// enabling dashboard event button
26+
this._$('#dashboard-event-btn').prop('disabled', false);
27+
this._$('#dashboard-event-btn').click(this.onEventButtonClick.bind(this));
28+
}
29+
30+
// When changes are made to the dashboard we get all the details for each of the
31+
// dashboard objects that were changed and compare it with their previous values.
32+
// The dashboardLayoutChangeDetails property is a map of dashboard obj3ct ids to
33+
// an array of dashboard layout changes.
34+
// Dashboard layout change events are invoked when dashboard objects are resized,
35+
// repositioned, added, and more. See DashboardLayoutChange in the API documentation
36+
// for all possible actions.
37+
// Extension reloads when worksheets are added / removed.
38+
private onDashboardLayoutChange(event: TableauEvent) {
39+
console.log(event);
40+
const dashboardEvent = event as DashboardLayoutChangedEvent;
41+
const dashboardEventDetails = dashboardEvent.dashboardLayoutChangeDetails;
42+
const dashboard = tableau.extensions.dashboardContent.dashboard;
43+
44+
// updating dashboard objects and storing the previous dashboard objects for referrence.
45+
const oldDashboardObjects = this.dashboardObjects;
46+
this.dashboardObjects = dashboard.objects;
47+
48+
// An empty dashboard layout change event may be invoked when loading an extension from the manifest.
49+
// In this case we ignore it and return.
50+
if (dashboardEventDetails === undefined || dashboardEventDetails.size === 0) {
51+
return;
52+
}
53+
54+
// Emptying previous content from the UI's change list.
55+
this._$('#dashboard-layout-change-list').empty();
56+
57+
// Updating UI's change list to display information on the current dashboard event.
58+
dashboardEventDetails.forEach((changesMade: DashboardLayoutChange[], dashboardObjectId: number) => {
59+
// getting dashboard object from its id
60+
const dashboardObject = dashboard.getDashboardObjectById(dashboardObjectId);
61+
62+
// building a div for the changes made to this dashboard object.
63+
const changesDiv = this._$('<div>');
64+
65+
// checking if this dashboard object was added as part of the event.
66+
if (changesMade.includes(tableau.DashboardLayoutChange.Added)) {
67+
const toAppend = this._$('<h6/>');
68+
toAppend.text(`Dashboard Object ${dashboardObjectId} added: "${dashboardObject.name}"`);
69+
changesDiv.append(toAppend);
70+
this._$('#dashboard-layout-change-list').append(changesDiv);
71+
return;
72+
}
73+
74+
// getting old dashboard object before event to compare it with the current one.
75+
const oldDashboardObject = oldDashboardObjects.find(o => o.id === dashboardObjectId);
76+
77+
// checking if this dashboard object was removed as part of the event.
78+
if (changesMade.includes(tableau.DashboardLayoutChange.Removed)) {
79+
const toAppend = this._$('<h6/>');
80+
toAppend.text(`Dashboard Object ${dashboardObjectId} removed: "${oldDashboardObject.name}"`);
81+
changesDiv.append(toAppend);
82+
this._$('#dashboard-layout-change-list').append(changesDiv);
83+
return;
84+
}
85+
86+
// the following dashboard changes are not mutually exclusive, so we list them together.
87+
const h6 = this._$('<h6/>');
88+
h6.text(`Dashboard Object ${dashboardObjectId}: "${dashboardObject.name}"`);
89+
changesDiv.append(h6);
90+
const ul = this._$('<ul/>');
91+
92+
// checking if the dashboard object had changes to its floating state.
93+
if (changesMade.includes(tableau.DashboardLayoutChange.IsFloatingChanged)) {
94+
const li = this._$('<li/>');
95+
li.text(`Floating is now ${dashboardObject.isFloating}, was ${oldDashboardObject.isFloating}`);
96+
ul.append(li);
97+
}
98+
99+
// checking if the dashbaord object had changes to its visibility.
100+
if (changesMade.includes(tableau.DashboardLayoutChange.IsVisibleChanged)) {
101+
const li = this._$('<li/>');
102+
li.text(`Visibility is now ${dashboardObject.isVisible}, was ${oldDashboardObject.isVisible}`);
103+
ul.append(li);
104+
}
105+
106+
// checking if the dashboard object was repositioned.
107+
if (changesMade.includes(tableau.DashboardLayoutChange.PositionChanged)) {
108+
const li = this._$('<li/>');
109+
const newPos = dashboardObject.position;
110+
const oldPos = oldDashboardObject.position;
111+
li.text(`Position is now (${newPos.x},${newPos.y}), was (${oldPos.x},${oldPos.y})`);
112+
ul.append(li);
113+
}
114+
115+
// checking if the dashboard object was resized.
116+
if (changesMade.includes(tableau.DashboardLayoutChange.SizeChanged)) {
117+
const li = this._$('<li/>');
118+
const newSize = dashboardObject.size;
119+
const oldSize = oldDashboardObject.size;
120+
li.text(`Size is now ${newSize.width}x${newSize.height}, was ${oldSize.width}x${oldSize.height}`);
121+
ul.append(li);
122+
}
123+
124+
// checking if the dashboard object was renamed.
125+
if (changesMade.includes(tableau.DashboardLayoutChange.NameChanged)) {
126+
const li = this._$('<li/>');
127+
li.text(`Name is now "${dashboardObject.name}", was "${oldDashboardObject.name}"`);
128+
ul.append(li);
129+
}
130+
131+
changesDiv.append(ul);
132+
this._$('#dashboard-layout-change-list').append(changesDiv);
133+
});
134+
}
135+
136+
// This function adds a dashboard event if there is not one already, and removes it if there is.
137+
private onEventButtonClick() {
138+
const dashboard = tableau.extensions.dashboardContent.dashboard;
139+
if ($('#dashboard-event-btn').text() === 'Add Dashboard Event') {
140+
dashboard.addEventListener(tableau.TableauEventType.DashboardLayoutChanged,
141+
(event) => this.onDashboardLayoutChange(event));
142+
$('#dashboard-event-btn').text('Remove Dashboard Event');
143+
} else {
144+
dashboard.removeEventListener(tableau.TableauEventType.DashboardLayoutChanged,
145+
(event) => this.onDashboardLayoutChange(event));
146+
$('#dashboard-layout-change-list').empty();
147+
$('#dashboard-event-btn').text('Add Dashboard Event');
148+
}
149+
}
150+
}
151+
152+
console.log('Initializing DashboardLayout extension.');
153+
await new DashboardLayout($).initialize();
154+
})();
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<style>
4+
.tooltip-header {
5+
position: relative;
6+
display: block;
7+
}
8+
9+
.tooltip-header .tooltiptext {
10+
visibility: hidden;
11+
width: 250px;
12+
background-color: rgb(223, 221, 233);
13+
text-align: center;
14+
border-radius: 6px;
15+
padding: 5px 0;
16+
position: absolute;
17+
z-index: 1;
18+
bottom: 125%;
19+
left: 50%;
20+
margin-left: -60px;
21+
opacity: 0;
22+
transition: opacity 0.3s;
23+
}
24+
25+
.tooltip-header .tooltiptext::after {
26+
content: "";
27+
position: absolute;
28+
top: 100%;
29+
left: 50%;
30+
margin-left: -5px;
31+
border-width: 5px;
32+
border-style: solid;
33+
border-color: rgb(223, 221, 233) transparent transparent transparent;
34+
}
35+
36+
.tooltip-header:hover .tooltiptext {
37+
visibility: visible;
38+
opacity: 1;
39+
}
40+
41+
</style>
42+
<head>
43+
<title>Tableau Formatting Demo</title>
44+
45+
<!-- jQuery -->
46+
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
47+
48+
<!-- Bootstrap -->
49+
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
50+
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
51+
52+
<!-- Extensions Library (this will be hosted on a CDN eventually) -->
53+
<script src="../../lib/tableau.extensions.1.latest.js"></script>
54+
55+
<!-- Our webpack'd extension's code -->
56+
<script src="../../dist/formatting.js"></script>
57+
</head>
58+
<body>
59+
<div class="container">
60+
<div>
61+
<h1>Tableau Formatting Sample</h1>
62+
<div id="formattingExample"></div>
63+
</div>
64+
</div>
65+
</body>
66+
</html>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest manifest-version="0.1" xmlns="http://www.tableau.com/xml/extension_manifest">
3+
<dashboard-extension id="com.tableau.extensions.samples.formatting" extension-version="0.6.0">
4+
<default-locale>en_US</default-locale>
5+
<name resource-id="name"/>
6+
<description>Tableau Formatting Sample</description>
7+
<author name="tableau" email="[email protected]" organization="tableau" website="https://www.tableau.com"/>
8+
<min-api-version>1.1</min-api-version>
9+
<source-location>
10+
<url>http://localhost:8765/Samples-Typescript/Formatting/formatting.html</url>
11+
</source-location>
12+
<icon>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</icon>
13+
</dashboard-extension>
14+
<resources>
15+
<resource id="name">
16+
<text locale="en_US">Tableau Formatting Sample</text>
17+
</resource>
18+
</resources>
19+
</manifest>
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import * as React from 'react';
2+
import * as ReactDOM from 'react-dom';
3+
4+
// Wrap everything in an anonymous function to avoid polluting the global namespace
5+
(async () => {
6+
7+
class Formatting {
8+
// This is the entry point into the extension. It initializes the Tableau Extensions Api, and then
9+
// will create elements with appropriate class names to get Tableau formatting
10+
public async initialize() {
11+
console.log('Initializing extension API');
12+
await tableau.extensions.initializeAsync();
13+
await this.Render();
14+
}
15+
16+
private async Render() {
17+
if (tableau.extensions.environment.workbookFormatting) {
18+
await this.RenderFormatting();
19+
} else {
20+
await this.RenderInfoMissing();
21+
}
22+
}
23+
24+
private async RenderFormatting() {
25+
const tooltipClassNames = 'tooltiptext ' + tableau.ClassNameKey.Tooltip;
26+
27+
ReactDOM.render(<>
28+
<h2 className={tableau.ClassNameKey.WorksheetTitle}>Subheader, using tableau-worksheet-title class</h2>
29+
<text className={tableau.ClassNameKey.Worksheet}>Text, using tableau-worksheet class</text>
30+
<h3 className='tooltip-header'>Hover to see tooltip text, which is using tableau-tooltip class
31+
<span className={tooltipClassNames}>Tooltip text, using tableau-tooltip class</span>
32+
</h3>
33+
<li className={tableau.ClassNameKey.StoryTitle}>Bullet Point, using tableau-story-title class</li>
34+
<text className={tableau.ClassNameKey.DashboardTitle}>Text, using tableau-dashboard-title class</text>
35+
</>, document.getElementById('formattingExample'));
36+
}
37+
38+
private async RenderInfoMissing() {
39+
const message = 'Tableau formatting information for extensions is missing from this version of Tableau.';
40+
41+
ReactDOM.render(<>
42+
<div style={{color: 'blue'}}>{message}</div>
43+
</>, document.getElementById('formattingExample'));
44+
}
45+
}
46+
47+
console.log('Initializing Formatting extension.');
48+
await new Formatting().initialize();
49+
})();

0 commit comments

Comments
 (0)