@sumboard/sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,367 @@
1
+ # Sumboard SDK
2
+
3
+ The Sumboard SDK is a powerful tool for creating and embedding interactive dashboards into your web applications.</br>
4
+ This documentation will guide you through the installation, frontend integration, backend integration, and filter usage processes.
5
+
6
+ ### Sumboard dashboards can be embedded in three different ways
7
+
8
+ - **Simple dashboard embed**: This involves displaying a dashboard in your application as you see it in the Sumboard Editor, without any predefined filters.
9
+
10
+ - **Embed dashboard with static token parameter**: This approach involves embedding a dashboard and filtering it with a parameter that comes from your application. This is often used when you want to provide the same dashboard for multiple users from your application, and you want each user to see their own data. This is usually achieved by sending a parameter like user_id in the token.
11
+
12
+ - **Embed dashboard with your application filters**: With this approach, you can have full control of the interactive filters for the dashboard. You can combine it with token parameters to offer your users a dashboard with their own data and have full control of the filters they can apply to it.
13
+
14
+ ## Table of Contents
15
+ - [Installation](#installation)
16
+ - [Simple dashboard embed](#simple-dashboard-embed)
17
+ - [Generating a Sumboard Token](#generating-a-sumboard-token)
18
+ - [Simple dashboard embed demo](#simple-dashboard-embed-demo)
19
+ - [Embed dashboard with static token parameter](#embed-dashboard-with-static-token-parameter)
20
+ - [Embed dashboard with your application filters](#embed-dashboard-with-your-application-filters)
21
+ - [Basic Filter Structure](#basic-filter-structure)
22
+ - [Filter Types](#filter-types)
23
+ - [TimeRange](#timerange-filter-filtertypetimerange)
24
+ - [Aggregation](#aggregation-filter-filtertypeaggregation)
25
+ - [Select](#select-filter-filtertypeselect)
26
+ - [Unknown](#unknown-custom-filter-filtertypeunknown)
27
+ - [Filter implementation](#filter-implementation)
28
+ - [Implementing filters during SDK initialization](#implementing-filters-during-sdk-initialization)
29
+ - [Changing filters after SDK initialization](#changing-filters-after-sdk-initialization)
30
+ - [Localize your dashboard](#localize-your-dashboard)
31
+ ## Installation
32
+ To install the Sumboard SDK, run the following command:
33
+ ```shell
34
+ npm install @sumboard/sdk
35
+ ```
36
+
37
+ ## Simple dashboard embed
38
+
39
+ Here we will show you how to embed a simple dashboard in your application using the Sumboard SDK.
40
+
41
+ This code initializes the Zeelix SDK and fetches a token from the backend server. It then initializes the Sumboard dashboard by passing the token and dashboard ID to the `init()` method of the SDK.
42
+
43
+ ```ts
44
+ import { Zeelix } from '@sumboard/sdk';
45
+
46
+ const sumboard = new Zeelix();
47
+
48
+ fetch('<https://your-backend.com/api/token>')
49
+ .then<{ token: string }>((response) => response.json())
50
+ .then(({ token }) => sumboard.init({ token, dashboardId: '<DASHBOARD_ID>' }));
51
+ ```
52
+
53
+ Replace `<https://your-backend.com/api/token>` with the URL of the API endpoint that your backend uses to generate tokens and `<DASHBOARD_ID>` with the ID of the dashboard you want to embed.
54
+
55
+ To display the dashboard in your application, add a `<div>` element with the specified width and height, and set the id attribute to `zeelix`:
56
+
57
+ ```html
58
+ <div id="zeelix" style="width: 1000px;height: 500px;"></div>
59
+ ```
60
+
61
+ ### Generating a Sumboard Token
62
+
63
+ To generate a Sumboard token, create an endpoint on your backend that uses the company secret key and dashboard shared token to generate and return the token. Here's an example of how to generate a Sumboard token in a Node.js backend:
64
+
65
+ ```ts
66
+ import { FiltersValues } from '@sumboard/types';
67
+ import { sign } from 'jsonwebtoken';
68
+
69
+ const st = '<DASHBOARD_SHARED_TOKEN>';
70
+ const companySecretKey = '<COMPANY_SECRET_KEY>';
71
+
72
+ const token = sign({ st }, companySecretKey);
73
+ ```
74
+
75
+ Replace `<DASHBOARD_SHARED_TOKEN>` with your dashboard's shared token and `<COMPANY_SECRET_KEY>` with your company's secret key. Once you have the token, pass it to the Sumboard SDK's init method to initialize the SDK in your frontend application.
76
+
77
+ ### Simple dashboard embed demo
78
+ You can also test this code in this [StackBlitz Demo](https://stackblitz.com/edit/zeelix-init?file=index.ts)
79
+
80
+ > **Note**</br>
81
+ > The demo uses a mock API to simulate fetching a token, and is for demonstration purposes only.
82
+
83
+ ## Embed dashboard with static token parameter
84
+
85
+ This is often used when you want to provide the same dashboard for multiple users from your application, and you want each user to see their own data.
86
+
87
+ Token type filters are initialized on the back-end as parameters, and should not be sent from the front-end. Here's an example of how to implement filters during token generation:
88
+
89
+ ```ts
90
+ const user: FilterUnknown['values'] = [
91
+ {
92
+ value: 'user-uuid',
93
+ label: 'FirstName, LastName',
94
+ }
95
+ ];
96
+
97
+ const params: FiltersValues = { user };
98
+
99
+ const token = sign({ st, params }, companySecretKey);
100
+ ```
101
+
102
+ In this example, we're defining a user filter with a single value of "user-uuid" and a label of "FirstName, LastName". We then create a `params` object containing the user filter, and use `sign` from the `jsonwebtoken` package to generate a token that includes the `params` object.
103
+
104
+ When the token is used to embed a Sumboard dashboard, the user filter will be automatically applied to the dashboard.
105
+
106
+ > **Warning**</br>
107
+ > It's important to note that the **security** of the token should be carefully considered, especially if sensitive data is being passed in the params object.
108
+
109
+ ## Embed dashboard with your application filters
110
+
111
+ The Sumboard SDK supports various types of filters, which are defined by the `FilterType` enumeration. The basic filter structure is used as the foundation for creating specific filter types like TimeRange, Aggregation, Select, and Unknown.
112
+
113
+ ### Basic Filter Structure
114
+
115
+ Here is the interface for the basic filter structure:
116
+ ```ts
117
+ export interface Filter<T extends FilterType, V = unknown> {
118
+ type: T;
119
+ place: FilterPlace;
120
+ values: FilterValue<V>[];
121
+ name?: string;
122
+ order?: number;
123
+ }
124
+ ```
125
+
126
+ The basic filter interface has the following properties:
127
+
128
+ - `type`: Represents the type of filter (TimeRange, Aggregation, Select, or Unknown).
129
+ - `place`: Specifies where the filter is displayed within the application, using the `FilterPlace` enumeration.
130
+ - `values`: An array of filter values.
131
+ - `name`: (optional): The name of the filter, which is displayed in the filter bar.
132
+ - `order`: (optional): The order in which the filter should appear in the filter bar.
133
+
134
+ Here is the FilterPlace enumeration:
135
+ ```ts
136
+ export enum FilterPlace {
137
+ Apps = 'apps',
138
+ Extern = 'extern',
139
+ Token = 'token',
140
+ }
141
+ ```
142
+
143
+ The FilterPlace enumeration represents where the filters are displayed and can have the following values:
144
+
145
+ - `FilterPlace.Apps`: Filters are displayed above the charts in the application. These filters can be changed from within the application, from outside the application (via the SDK), or from the token (when the backend generates the token).
146
+ - `FilterPlace.Extern`: Filters are outside the application. These filters can be changed from outside the application (via the SDK) or from the token (when the backend generates the token).
147
+ - `FilterPlace.Token`: Filters that are added to the token when the token is generated by a third party. These filters can be changed only from the token (when the backend generates the token).
148
+
149
+
150
+
151
+ ### Filter Types
152
+
153
+ Here is the interface for the filter types:
154
+ ```ts
155
+ export enum FilterType {
156
+ TimeRange = 'time_range',
157
+ Aggregation = 'aggregation',
158
+ Select = 'select',
159
+ Unknown = 'unknown',
160
+ }
161
+ ```
162
+
163
+ #### TimeRange Filter (`FilterType.TimeRange`)
164
+
165
+ The TimeRange filter is used for selecting a time range. It has a value in this structure `from~to[]`, where both `from` and `to` can be a custom range or a timestamp. The `TimeRangeType` type represents the various time range options supported by this filter.</br>
166
+
167
+ Here is the interface for the `TimeRange` filter:
168
+ ```ts
169
+ export type Time = number;
170
+
171
+ export enum CustomRange {
172
+ Today = 'today',
173
+ Yesterday = 'yesterday',
174
+ LastWeek = 'lastWeek',
175
+ LastMonth = 'lastMonth',
176
+ Last7Days = 'last7Days',
177
+ Last30Days = 'last30Days',
178
+ }
179
+
180
+ export type TimeRangeType =
181
+ | CustomRange.Today
182
+ | CustomRange.Yesterday
183
+ | CustomRange.LastWeek
184
+ | CustomRange.LastMonth
185
+ | CustomRange.Last7Days
186
+ | CustomRange.Last30Days
187
+ | `${Time}~${Time}`
188
+ | `${Time}~`
189
+ | `~${Time}`;
190
+
191
+ export type FilterTimeRange = Filter<FilterType.TimeRange, TimeRangeType>;
192
+ ```
193
+
194
+ These predefined ranges (Today, Yesterday, etc.) and custom time ranges (using `${Time}`) allow you to configure the TimeRange filter according to your needs.
195
+
196
+ #### Aggregation Filter (`FilterType.Aggregation`)
197
+
198
+ The Aggregation filter is used for aggregating data. It has a value in this structure `DateFormat[]`.
199
+
200
+ Here is the interface for the `Aggregation` filter:
201
+
202
+ ```ts
203
+ export enum DateFormat {
204
+ Hour = 'hour',
205
+ Day = 'day',
206
+ Week = 'week',
207
+ Month = 'month',
208
+ Quarter = 'quarter',
209
+ Year = 'year',
210
+ }
211
+
212
+ export type FilterAggregation = Filter<FilterType.Aggregation, DateFormat>;
213
+ ```
214
+
215
+ The `DateFormat` enumeration represents various aggregation options such as hour, day, week, month, quarter, and year. You can use the Aggregation filter to customize how your data is aggregated based on these options.
216
+
217
+ #### Select Filter (`FilterType.Select`)
218
+
219
+ The Select filter is used for filtering data by selected values from another query.
220
+
221
+ Here is the interface for the `Select` filter:
222
+
223
+ ```ts
224
+ export interface FilterSelect extends Filter<FilterType.Select, (string | number)[]> {}
225
+ ```
226
+
227
+ The `Select` filter allows you to filter your data based on the selected values, which can be strings or numbers, from another query. This can be useful for creating dependent filters or conditional data display based on user selections.
228
+
229
+ #### Unknown (Custom Filter) (`FilterType.Unknown`)
230
+
231
+ The `Unknown` (Custom Filter) is a filter that is allowed to be used in the `FilterPlace.Extern` or `FilterPlace.Token`
232
+
233
+ Here is the interface for the `Unknown` (Custom Filter):
234
+
235
+ ```ts
236
+ export type FilterUnknown<T = unknown> = Filter<FilterType.Unknown, T>;
237
+ ```
238
+
239
+ The `Unknown` (Custom Filter) allows you to create custom filters with user-defined value structures. This can be useful for integrating filters that are not part of the predefined filter types and can be used in external or token-based filter placement.
240
+
241
+
242
+ ### Filter implementation
243
+
244
+ #### Implementing filters during SDK initialization
245
+
246
+ To implement filters during initialization, create a `filters` object containing the desired filter configurations and pass it to the `sumboard.init()` method along with the token and dashboard ID.
247
+
248
+ Here's an example of how to implement filters on initialization:
249
+ ```ts
250
+ const filters: FiltersMap<FilterType> = {
251
+ aggregation: {
252
+ type: FilterType.Aggregation,
253
+ place: FilterPlace.Apps,
254
+ values: [
255
+ {
256
+ value: DateFormat.Month,
257
+ label: 'Month',
258
+ },
259
+ ],
260
+ },
261
+ timeRange: {
262
+ type: FilterType.TimeRange,
263
+ place: FilterPlace.Apps,
264
+ values: [
265
+ {
266
+ value: CustomRange.Last30Days,
267
+ label: 'Last 30 days',
268
+ }
269
+ ]
270
+ },
271
+ users: {
272
+ type: FilterType.Select,
273
+ place: FilterPlace.Apps,
274
+ values: [
275
+ {
276
+ value: ['user-uuid-1', 'user-uuid-2'],
277
+ label: 'User Name 1, User Name 2',
278
+ }
279
+ ]
280
+ }
281
+ };
282
+
283
+
284
+ fetch('https://your-backend.com/api/token')
285
+ .then<{ token: string }>((response) => response.json())
286
+ .then(({ token }) => sumboard.init({ token, filters, dashboardId: '<DASHBOARD_ID>' }));
287
+ ```
288
+
289
+ You can also test this code in this [StackBlitz Demo](https://stackblitz.com/edit/zeelix-init-filter?file=index.ts)
290
+
291
+ > **Note**</br>
292
+ > The demo uses a mock API to simulate fetching a token, and is for demonstration purposes only.
293
+
294
+ #### Changing filters after SDK initialization
295
+
296
+ To change filters after initialization, you can call the changeFilters method of the Sumboard instance. This method takes an object where each key represents the name of the filter you want to change, and the value is an object containing the updated values for that filter.
297
+
298
+ Here is an example of changing the Aggregation filter:
299
+
300
+ ```ts
301
+ document.getElementById('aggregation').onchange = ({ target }) => {
302
+ const value = (target as HTMLSelectElement).value as DateFormat;
303
+
304
+ sumboard.changeFilters({
305
+ aggregation: {
306
+ type: FilterType.Aggregation,
307
+ place: FilterPlace.Extern,
308
+ values: [{ value }],
309
+ },
310
+ });
311
+ };
312
+ ```
313
+
314
+ In this example, we're changing the aggregation filter to a new value specified by the user through an HTML select element. Note that the changeFilters method can change one or several filters at once, depending on the keys of the object passed as an argument.
315
+
316
+ You can also test this code in this [StackBlitz Demo](https://stackblitz.com/edit/zeelix-change-filters?file=index.ts)
317
+
318
+ > **Note**</br>
319
+ > The demo uses a mock API to simulate fetching a token, and is for demonstration purposes only.
320
+
321
+ ## Localize your dashboard
322
+
323
+ In order to provide your users with a different language, timezone and localization options, you can pass a `config` parameter when you generate the token on server side.
324
+
325
+ ```ts
326
+ import { FiltersValues } from '@sumboard/types';
327
+ import { sign } from 'jsonwebtoken';
328
+
329
+ interface Config {
330
+ timezone?: string,
331
+ language?: string,
332
+ columns?: {
333
+ currency?: { locale: string },
334
+ number?: { locale: string },
335
+ date?: { locale: string },
336
+ }
337
+ }
338
+
339
+ const st = '<DASHBOARD_SHARED_TOKEN>';
340
+
341
+ const companySecretKey = '<COMPANY_SECRET_KEY>';
342
+
343
+ const config: Config = {
344
+ timezone: '+0200',
345
+ language: 'en',
346
+ columns: {
347
+ currency: { locale: 'en' },
348
+ number: { locale: 'en' },
349
+ date: { locale: 'en' },
350
+ }
351
+ };
352
+
353
+ const token = sign({ st, config }, companySecretKey);
354
+ ```
355
+
356
+
357
+ The Config interface provides additional configuration options that can be passed during the initialization of the Sumboard Token. This interface includes the following properties:
358
+
359
+ - `timezone` (optional): A string that represents the timezone of the data being displayed on the dashboard.
360
+ - `language` (optional): A string that represents the language of the dashboard.
361
+ - `columns` (optional): An object that contains configuration options for the currency, number, and date columns.
362
+
363
+ The columns property of the Config interface has the following sub-properties:
364
+
365
+ - `currency` (optional): An object that contains a locale string that represents the currency formatting to be used for columns that contain currency data.
366
+ - `number` (optional): An object that contains a locale string that represents the number formatting to be used for columns that contain numerical data.
367
+ - `date` (optional): An object that contains a locale string that represents the date formatting to be used for columns that contain date data.
@@ -0,0 +1,48 @@
1
+ export class Zeelix {
2
+ constructor() {
3
+ this._listener = this._receiveMessage.bind(this);
4
+ this.init = (config) => {
5
+ this._config = config;
6
+ window.addEventListener('message', this._listener, false);
7
+ return this._mountIframe();
8
+ };
9
+ this.changeFilters = (filters) => {
10
+ this._iframe.contentWindow?.postMessage({ type: "CHANGE_FILTERS", filters }, '*');
11
+ };
12
+ this._mountIframe = () => {
13
+ return new Promise((resolve) => {
14
+ const iframe = document.createElement('iframe');
15
+ iframe.onload = () => resolve();
16
+ iframe.src = this._generateIframeSrc();
17
+ iframe.width = '100%';
18
+ iframe.height = '100%';
19
+ iframe.style.border = 'none';
20
+ iframe.style.outline = 'none';
21
+ this._iframe = iframe;
22
+ const wrapper = document.getElementById('zeelix');
23
+ if (!wrapper)
24
+ throw new Error('not found HTMLElement with id "zeelix"');
25
+ wrapper.appendChild(iframe);
26
+ });
27
+ };
28
+ this._generateIframeSrc = () => {
29
+ if ('dashboardPageId' in this._config) {
30
+ return `https://app.sumboard.io/embed-page/${this._config.dashboardPageId}`;
31
+ }
32
+ return `https://app.sumboard.io/embed/${this._config.dashboardId}`;
33
+ };
34
+ }
35
+ destroy() {
36
+ window.removeEventListener('message', this._listener, false);
37
+ }
38
+ _receiveMessage({ data }) {
39
+ switch (data.type) {
40
+ case "BOOTSTRAP_DONE":
41
+ return this._initDashboard();
42
+ }
43
+ }
44
+ _initDashboard() {
45
+ this._iframe.contentWindow?.postMessage({ type: "INIT_IFRAME", config: this._config }, '*');
46
+ }
47
+ }
48
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2RrLm1vZHVsZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL3Nkay9zcmMvbGliL3Nkay5tb2R1bGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBSUEsTUFBTSxPQUFPLE1BQU07SUFBbkI7UUFJVSxjQUFTLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQW1DLElBQUksQ0FBQyxDQUFDO1FBRXRGLFNBQUksR0FBRyxDQUFDLE1BQWMsRUFBaUIsRUFBRTtZQUN2QyxJQUFJLENBQUMsT0FBTyxHQUFHLE1BQU0sQ0FBQztZQUl0QixNQUFNLENBQUMsZ0JBQWdCLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxTQUFVLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFFM0QsT0FBTyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7UUFDN0IsQ0FBQyxDQUFDO1FBSUYsa0JBQWEsR0FBRyxDQUFDLE9BQW1CLEVBQVEsRUFBRTtZQUM1QyxJQUFJLENBQUMsT0FBTyxDQUFDLGFBQWEsRUFBRSxXQUFXLENBQUMsRUFBRSxJQUFJLGtCQUFxQixFQUFFLE9BQU8sRUFBRSxFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQ3ZGLENBQUMsQ0FBQztRQU1NLGlCQUFZLEdBQUcsR0FBa0IsRUFBRTtZQUN6QyxPQUFPLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUU7Z0JBQzdCLE1BQU0sTUFBTSxHQUFHLFFBQVEsQ0FBQyxhQUFhLENBQUMsUUFBUSxDQUFDLENBQUM7Z0JBRWhELE1BQU0sQ0FBQyxNQUFNLEdBQUcsR0FBRyxFQUFFLENBQUMsT0FBTyxFQUFFLENBQUM7Z0JBRWhDLE1BQU0sQ0FBQyxHQUFHLEdBQUcsSUFBSSxDQUFDLGtCQUFrQixFQUFFLENBQUM7Z0JBRXZDLE1BQU0sQ0FBQyxLQUFLLEdBQUcsTUFBTSxDQUFDO2dCQUN0QixNQUFNLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztnQkFDdkIsTUFBTSxDQUFDLEtBQUssQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO2dCQUM3QixNQUFNLENBQUMsS0FBSyxDQUFDLE9BQU8sR0FBRyxNQUFNLENBQUM7Z0JBRTlCLElBQUksQ0FBQyxPQUFPLEdBQUcsTUFBTSxDQUFDO2dCQUV0QixNQUFNLE9BQU8sR0FBRyxRQUFRLENBQUMsY0FBYyxDQUFDLFFBQVEsQ0FBQyxDQUFDO2dCQUVsRCxJQUFJLENBQUMsT0FBTztvQkFBRSxNQUFNLElBQUksS0FBSyxDQUFDLHdDQUF3QyxDQUFDLENBQUM7Z0JBRXhFLE9BQU8sQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDOUIsQ0FBQyxDQUFDLENBQUM7UUFDTCxDQUFDLENBQUM7UUFtQk0sdUJBQWtCLEdBQUcsR0FBVyxFQUFFO1lBQ3hDLElBQUksaUJBQWlCLElBQUksSUFBSSxDQUFDLE9BQU8sRUFBRTtnQkFDckMsT0FBTyxzQ0FBc0MsSUFBSSxDQUFDLE9BQU8sQ0FBQyxlQUFlLEVBQUUsQ0FBQzthQUM3RTtZQUVELE9BQU8saUNBQWlDLElBQUksQ0FBQyxPQUFPLENBQUMsV0FBVyxFQUFFLENBQUM7UUFDckUsQ0FBQyxDQUFDO0lBQ0osQ0FBQztJQW5EQyxPQUFPO1FBQ0wsTUFBTSxDQUFDLG1CQUFtQixDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsU0FBVSxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBQ2hFLENBQUM7SUEyQk8sZUFBZSxDQUFDLEVBQUUsSUFBSSxFQUFxQjtRQUNqRCxRQUFRLElBQUksQ0FBQyxJQUFJLEVBQUU7WUFDakI7Z0JBQ0UsT0FBTyxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7U0FDaEM7SUFDSCxDQUFDO0lBSU8sY0FBYztRQUNwQixJQUFJLENBQUMsT0FBTyxDQUFDLGFBQWEsRUFBRSxXQUFXLENBQUMsRUFBRSxJQUFJLGVBQWtCLEVBQUUsTUFBTSxFQUFFLElBQUksQ0FBQyxPQUFPLEVBQUUsRUFBRSxHQUFHLENBQUMsQ0FBQztJQUNqRyxDQUFDO0NBV0YiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBGaWx0ZXJzTWFwIH0gZnJvbSAnQHN1bWJvYXJkL3R5cGVzJztcblxuaW1wb3J0IHsgQ29uZmlnLCBFdmVudCwgTWVzc2FnZSB9IGZyb20gJy4vc2tkLnR5cGVzJztcblxuZXhwb3J0IGNsYXNzIFplZWxpeCB7XG4gIHByaXZhdGUgX2lmcmFtZSE6IEhUTUxJRnJhbWVFbGVtZW50O1xuICBwcml2YXRlIF9jb25maWchOiBDb25maWc7XG5cbiAgcHJpdmF0ZSBfbGlzdGVuZXIgPSB0aGlzLl9yZWNlaXZlTWVzc2FnZS5iaW5kPFdpbmRvd0V2ZW50SGFuZGxlcnNbJ29ubWVzc2FnZSddPih0aGlzKTtcblxuICBpbml0ID0gKGNvbmZpZzogQ29uZmlnKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgdGhpcy5fY29uZmlnID0gY29uZmlnO1xuICAgIC8qKlxuICAgICAqIGxpc3RlbmVyIG1lc3NhZ2VzIGZyb20gaWZyYW1lXG4gICAgICovXG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ21lc3NhZ2UnLCB0aGlzLl9saXN0ZW5lciEsIGZhbHNlKTtcblxuICAgIHJldHVybiB0aGlzLl9tb3VudElmcmFtZSgpO1xuICB9O1xuICAvKipcbiAgICogdW5kZWZpbmVkIGlzIGZvciBmaWx0ZXIgdGhhdCB5b3Ugd2FudCB0byByZW1vdmVcbiAgICovXG4gIGNoYW5nZUZpbHRlcnMgPSAoZmlsdGVyczogRmlsdGVyc01hcCk6IHZvaWQgPT4ge1xuICAgIHRoaXMuX2lmcmFtZS5jb250ZW50V2luZG93Py5wb3N0TWVzc2FnZSh7IHR5cGU6IEV2ZW50LkNoYW5nZUZpbHRlcnMsIGZpbHRlcnMgfSwgJyonKTtcbiAgfTtcblxuICBkZXN0cm95KCk6IHZvaWQge1xuICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKCdtZXNzYWdlJywgdGhpcy5fbGlzdGVuZXIhLCBmYWxzZSk7XG4gIH1cblxuICBwcml2YXRlIF9tb3VudElmcmFtZSA9ICgpOiBQcm9taXNlPHZvaWQ+ID0+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcbiAgICAgIGNvbnN0IGlmcmFtZSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2lmcmFtZScpO1xuXG4gICAgICBpZnJhbWUub25sb2FkID0gKCkgPT4gcmVzb2x2ZSgpO1xuXG4gICAgICBpZnJhbWUuc3JjID0gdGhpcy5fZ2VuZXJhdGVJZnJhbWVTcmMoKTtcblxuICAgICAgaWZyYW1lLndpZHRoID0gJzEwMCUnO1xuICAgICAgaWZyYW1lLmhlaWdodCA9ICcxMDAlJztcbiAgICAgIGlmcmFtZS5zdHlsZS5ib3JkZXIgPSAnbm9uZSc7XG4gICAgICBpZnJhbWUuc3R5bGUub3V0bGluZSA9ICdub25lJztcblxuICAgICAgdGhpcy5faWZyYW1lID0gaWZyYW1lO1xuXG4gICAgICBjb25zdCB3cmFwcGVyID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3plZWxpeCcpO1xuXG4gICAgICBpZiAoIXdyYXBwZXIpIHRocm93IG5ldyBFcnJvcignbm90IGZvdW5kIEhUTUxFbGVtZW50IHdpdGggaWQgXCJ6ZWVsaXhcIicpO1xuXG4gICAgICB3cmFwcGVyLmFwcGVuZENoaWxkKGlmcmFtZSk7XG4gICAgfSk7XG4gIH07XG4gIC8qKlxuICAgKiByZWNlaXZlIG1lc3NhZ2UgZnJvbSBpZnJhbWVcbiAgICovXG4gIHByaXZhdGUgX3JlY2VpdmVNZXNzYWdlKHsgZGF0YSB9OiB7IGRhdGE6IE1lc3NhZ2UgfSk6IHZvaWQge1xuICAgIHN3aXRjaCAoZGF0YS50eXBlKSB7XG4gICAgICBjYXNlIEV2ZW50LkJvb3RzdHJhcERvbmU6XG4gICAgICAgIHJldHVybiB0aGlzLl9pbml0RGFzaGJvYXJkKCk7XG4gICAgfVxuICB9XG4gIC8qKlxuICAgKiBpbml0IGRhc2hib2FyZCB3aGVuIHplZWxpeCBpcyByZWFkeVxuICAgKi9cbiAgcHJpdmF0ZSBfaW5pdERhc2hib2FyZCgpOiB2b2lkIHtcbiAgICB0aGlzLl9pZnJhbWUuY29udGVudFdpbmRvdz8ucG9zdE1lc3NhZ2UoeyB0eXBlOiBFdmVudC5Jbml0SUZyYW1lLCBjb25maWc6IHRoaXMuX2NvbmZpZyB9LCAnKicpO1xuICB9XG4gIC8qKlxuICAgKiBnZW5lcmF0ZSBpZnJhbWUgc3JjIGZyb20gY29uZmlnXG4gICAqL1xuICBwcml2YXRlIF9nZW5lcmF0ZUlmcmFtZVNyYyA9ICgpOiBzdHJpbmcgPT4ge1xuICAgIGlmICgnZGFzaGJvYXJkUGFnZUlkJyBpbiB0aGlzLl9jb25maWcpIHtcbiAgICAgIHJldHVybiBgaHR0cHM6Ly9hcHAuc3VtYm9hcmQuaW8vZW1iZWQtcGFnZS8ke3RoaXMuX2NvbmZpZy5kYXNoYm9hcmRQYWdlSWR9YDtcbiAgICB9XG5cbiAgICByZXR1cm4gYGh0dHBzOi8vYXBwLnN1bWJvYXJkLmlvL2VtYmVkLyR7dGhpcy5fY29uZmlnLmRhc2hib2FyZElkfWA7XG4gIH07XG59XG4iXX0=
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2tkLnR5cGVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvc2RrL3NyYy9saWIvc2tkLnR5cGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBGaWx0ZXJzTWFwIH0gZnJvbSAnQHN1bWJvYXJkL3R5cGVzJztcblxuZXhwb3J0IGNvbnN0IGVudW0gRXZlbnQge1xuICBJbml0SUZyYW1lID0gJ0lOSVRfSUZSQU1FJyxcbiAgQ2hhbmdlRmlsdGVycyA9ICdDSEFOR0VfRklMVEVSUycsXG4gIEJvb3RzdHJhcERvbmUgPSAnQk9PVFNUUkFQX0RPTkUnLFxufVxuXG5leHBvcnQgaW50ZXJmYWNlIEJhc2VDb25maWcge1xuICB0b2tlbjogc3RyaW5nO1xuICAvKipcbiAgICogdW5kZWZpbmVkIGlzIGZvciBmaWx0ZXIgdGhhdCB5b3Ugd2FudCB0byByZW1vdmVcbiAgICovXG4gIGZpbHRlcnM/OiBGaWx0ZXJzTWFwO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIERhc2hib2FyZENvbmZpZyBleHRlbmRzIEJhc2VDb25maWcge1xuICBkYXNoYm9hcmRJZDogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIERhc2hib2FyZFBhZ2VDb25maWcgZXh0ZW5kcyBCYXNlQ29uZmlnIHtcbiAgZGFzaGJvYXJkUGFnZUlkOiBzdHJpbmc7XG59XG5cbmV4cG9ydCB0eXBlIENvbmZpZyA9IERhc2hib2FyZENvbmZpZyB8IERhc2hib2FyZFBhZ2VDb25maWc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgTWVzc2FnZUZpbHRlcnMgZXh0ZW5kcyBQaWNrPENvbmZpZywgJ2ZpbHRlcnMnPiB7XG4gIHR5cGU6IEV2ZW50LkNoYW5nZUZpbHRlcnM7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTWVzc2FnZUluaXQge1xuICB0eXBlOiBFdmVudC5Jbml0SUZyYW1lO1xuICBjb25maWc6IENvbmZpZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBNZXNzYWdlQm9vdHN0cmFwIHtcbiAgdHlwZTogRXZlbnQuQm9vdHN0cmFwRG9uZTtcbn1cblxuZXhwb3J0IHR5cGUgTWVzc2FnZSA9IE1lc3NhZ2VCb290c3RyYXAgfCBNZXNzYWdlRmlsdGVycyB8IE1lc3NhZ2VJbml0O1xuIl19
@@ -0,0 +1,3 @@
1
+ export * from './lib/sdk.module';
2
+ export * from './lib/skd.types';
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVibGljLWFwaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3Byb2plY3RzL3Nkay9zcmMvcHVibGljLWFwaS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFHQSxjQUFjLGtCQUFrQixDQUFDO0FBQ2pDLGNBQWMsaUJBQWlCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuICogUHVibGljIEFQSSBTdXJmYWNlIG9mIHNka1xuICovXG5leHBvcnQgKiBmcm9tICcuL2xpYi9zZGsubW9kdWxlJztcbmV4cG9ydCAqIGZyb20gJy4vbGliL3NrZC50eXBlcyc7XG4iXX0=
@@ -0,0 +1,2 @@
1
+ export * from './public-api';
2
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3VtYm9hcmQtc2RrLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vcHJvamVjdHMvc2RrL3NyYy9zdW1ib2FyZC1zZGsudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBSUEsY0FBYyxjQUFjLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEdlbmVyYXRlZCBidW5kbGUgaW5kZXguIERvIG5vdCBlZGl0LlxuICovXG5cbmV4cG9ydCAqIGZyb20gJy4vcHVibGljLWFwaSc7XG4iXX0=
@@ -0,0 +1,50 @@
1
+ class Zeelix {
2
+ constructor() {
3
+ this._listener = this._receiveMessage.bind(this);
4
+ this.init = (config) => {
5
+ this._config = config;
6
+ window.addEventListener('message', this._listener, false);
7
+ return this._mountIframe();
8
+ };
9
+ this.changeFilters = (filters) => {
10
+ this._iframe.contentWindow?.postMessage({ type: "CHANGE_FILTERS", filters }, '*');
11
+ };
12
+ this._mountIframe = () => {
13
+ return new Promise((resolve) => {
14
+ const iframe = document.createElement('iframe');
15
+ iframe.onload = () => resolve();
16
+ iframe.src = this._generateIframeSrc();
17
+ iframe.width = '100%';
18
+ iframe.height = '100%';
19
+ iframe.style.border = 'none';
20
+ iframe.style.outline = 'none';
21
+ this._iframe = iframe;
22
+ const wrapper = document.getElementById('zeelix');
23
+ if (!wrapper)
24
+ throw new Error('not found HTMLElement with id "zeelix"');
25
+ wrapper.appendChild(iframe);
26
+ });
27
+ };
28
+ this._generateIframeSrc = () => {
29
+ if ('dashboardPageId' in this._config) {
30
+ return `https://app.sumboard.io/embed-page/${this._config.dashboardPageId}`;
31
+ }
32
+ return `https://app.sumboard.io/embed/${this._config.dashboardId}`;
33
+ };
34
+ }
35
+ destroy() {
36
+ window.removeEventListener('message', this._listener, false);
37
+ }
38
+ _receiveMessage({ data }) {
39
+ switch (data.type) {
40
+ case "BOOTSTRAP_DONE":
41
+ return this._initDashboard();
42
+ }
43
+ }
44
+ _initDashboard() {
45
+ this._iframe.contentWindow?.postMessage({ type: "INIT_IFRAME", config: this._config }, '*');
46
+ }
47
+ }
48
+
49
+ export { Zeelix };
50
+ //# sourceMappingURL=sumboard-sdk.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sumboard-sdk.mjs","sources":["../../../projects/sdk/src/lib/sdk.module.ts"],"sourcesContent":["import { FiltersMap } from '@sumboard/types';\n\nimport { Config, Event, Message } from './skd.types';\n\nexport class Zeelix {\n private _iframe!: HTMLIFrameElement;\n private _config!: Config;\n\n private _listener = this._receiveMessage.bind<WindowEventHandlers['onmessage']>(this);\n\n init = (config: Config): Promise<void> => {\n this._config = config;\n /**\n * listener messages from iframe\n */\n window.addEventListener('message', this._listener!, false);\n\n return this._mountIframe();\n };\n /**\n * undefined is for filter that you want to remove\n */\n changeFilters = (filters: FiltersMap): void => {\n this._iframe.contentWindow?.postMessage({ type: Event.ChangeFilters, filters }, '*');\n };\n\n destroy(): void {\n window.removeEventListener('message', this._listener!, false);\n }\n\n private _mountIframe = (): Promise<void> => {\n return new Promise((resolve) => {\n const iframe = document.createElement('iframe');\n\n iframe.onload = () => resolve();\n\n iframe.src = this._generateIframeSrc();\n\n iframe.width = '100%';\n iframe.height = '100%';\n iframe.style.border = 'none';\n iframe.style.outline = 'none';\n\n this._iframe = iframe;\n\n const wrapper = document.getElementById('zeelix');\n\n if (!wrapper) throw new Error('not found HTMLElement with id \"zeelix\"');\n\n wrapper.appendChild(iframe);\n });\n };\n /**\n * receive message from iframe\n */\n private _receiveMessage({ data }: { data: Message }): void {\n switch (data.type) {\n case Event.BootstrapDone:\n return this._initDashboard();\n }\n }\n /**\n * init dashboard when zeelix is ready\n */\n private _initDashboard(): void {\n this._iframe.contentWindow?.postMessage({ type: Event.InitIFrame, config: this._config }, '*');\n }\n /**\n * generate iframe src from config\n */\n private _generateIframeSrc = (): string => {\n if ('dashboardPageId' in this._config) {\n return `https://app.sumboard.io/embed-page/${this._config.dashboardPageId}`;\n }\n\n return `https://app.sumboard.io/embed/${this._config.dashboardId}`;\n };\n}\n"],"names":[],"mappings":"MAIa,MAAM,CAAA;AAAnB,IAAA,WAAA,GAAA;QAIU,IAAS,CAAA,SAAA,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAAmC,IAAI,CAAC,CAAC;AAEtF,QAAA,IAAA,CAAA,IAAI,GAAG,CAAC,MAAc,KAAmB;AACvC,YAAA,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;YAItB,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAAC,SAAU,EAAE,KAAK,CAAC,CAAC;AAE3D,YAAA,OAAO,IAAI,CAAC,YAAY,EAAE,CAAC;AAC7B,SAAC,CAAC;AAIF,QAAA,IAAA,CAAA,aAAa,GAAG,CAAC,OAAmB,KAAU;AAC5C,YAAA,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,WAAW,CAAC,EAAE,IAAI,EAAA,gBAAqB,EAAE,OAAO,EAAE,EAAE,GAAG,CAAC,CAAC;AACvF,SAAC,CAAC;QAMM,IAAY,CAAA,YAAA,GAAG,MAAoB;AACzC,YAAA,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,KAAI;gBAC7B,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;gBAEhD,MAAM,CAAC,MAAM,GAAG,MAAM,OAAO,EAAE,CAAC;AAEhC,gBAAA,MAAM,CAAC,GAAG,GAAG,IAAI,CAAC,kBAAkB,EAAE,CAAC;AAEvC,gBAAA,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC;AACtB,gBAAA,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;AACvB,gBAAA,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC;AAC7B,gBAAA,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC;AAE9B,gBAAA,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;gBAEtB,MAAM,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;AAElD,gBAAA,IAAI,CAAC,OAAO;AAAE,oBAAA,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;AAExE,gBAAA,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;AAC9B,aAAC,CAAC,CAAC;AACL,SAAC,CAAC;QAmBM,IAAkB,CAAA,kBAAA,GAAG,MAAa;AACxC,YAAA,IAAI,iBAAiB,IAAI,IAAI,CAAC,OAAO,EAAE;AACrC,gBAAA,OAAO,sCAAsC,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC;AAC7E,aAAA;AAED,YAAA,OAAO,iCAAiC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;AACrE,SAAC,CAAC;KACH;IAnDC,OAAO,GAAA;QACL,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,IAAI,CAAC,SAAU,EAAE,KAAK,CAAC,CAAC;KAC/D;IA2BO,eAAe,CAAC,EAAE,IAAI,EAAqB,EAAA;QACjD,QAAQ,IAAI,CAAC,IAAI;AACf,YAAA,KAAA,gBAAA;AACE,gBAAA,OAAO,IAAI,CAAC,cAAc,EAAE,CAAC;AAChC,SAAA;KACF;IAIO,cAAc,GAAA;QACpB,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,WAAW,CAAC,EAAE,IAAI,EAAA,aAAkB,EAAE,MAAM,EAAE,IAAI,CAAC,OAAO,EAAE,EAAE,GAAG,CAAC,CAAC;KAChG;AAWF;;;;"}
package/index.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ /// <amd-module name="@sumboard/sdk" />
2
+ export * from './public-api';
@@ -0,0 +1,14 @@
1
+ import { FiltersMap } from '@sumboard/types';
2
+ import { Config } from './skd.types';
3
+ export declare class Zeelix {
4
+ private _iframe;
5
+ private _config;
6
+ private _listener;
7
+ init: (config: Config) => Promise<void>;
8
+ changeFilters: (filters: FiltersMap) => void;
9
+ destroy(): void;
10
+ private _mountIframe;
11
+ private _receiveMessage;
12
+ private _initDashboard;
13
+ private _generateIframeSrc;
14
+ }
@@ -0,0 +1,28 @@
1
+ import { FiltersMap } from '@sumboard/types';
2
+ export declare const enum Event {
3
+ InitIFrame = "INIT_IFRAME",
4
+ ChangeFilters = "CHANGE_FILTERS",
5
+ BootstrapDone = "BOOTSTRAP_DONE"
6
+ }
7
+ export interface BaseConfig {
8
+ token: string;
9
+ filters?: FiltersMap;
10
+ }
11
+ export interface DashboardConfig extends BaseConfig {
12
+ dashboardId: string;
13
+ }
14
+ export interface DashboardPageConfig extends BaseConfig {
15
+ dashboardPageId: string;
16
+ }
17
+ export type Config = DashboardConfig | DashboardPageConfig;
18
+ export interface MessageFilters extends Pick<Config, 'filters'> {
19
+ type: Event.ChangeFilters;
20
+ }
21
+ export interface MessageInit {
22
+ type: Event.InitIFrame;
23
+ config: Config;
24
+ }
25
+ export interface MessageBootstrap {
26
+ type: Event.BootstrapDone;
27
+ }
28
+ export type Message = MessageBootstrap | MessageFilters | MessageInit;
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "@sumboard/sdk",
3
+ "version": "1.0.0",
4
+ "dependencies": {
5
+ "tslib": "^2.3.1",
6
+ "@sumboard/types": "^1.0.0"
7
+ },
8
+ "description": "This library is sdk for sumboard.io",
9
+ "directories": {
10
+ "lib": "lib"
11
+ },
12
+ "author": "",
13
+ "license": "ISC",
14
+ "module": "fesm2022/sumboard-sdk.mjs",
15
+ "typings": "index.d.ts",
16
+ "exports": {
17
+ "./package.json": {
18
+ "default": "./package.json"
19
+ },
20
+ ".": {
21
+ "types": "./index.d.ts",
22
+ "esm2022": "./esm2022/sumboard-sdk.mjs",
23
+ "esm": "./esm2022/sumboard-sdk.mjs",
24
+ "default": "./fesm2022/sumboard-sdk.mjs"
25
+ }
26
+ },
27
+ "sideEffects": false
28
+ }
@@ -0,0 +1,2 @@
1
+ export * from './lib/sdk.module';
2
+ export * from './lib/skd.types';