@sigmacomputing/plugin 1.1.0-alpha.2 → 1.1.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/CHANGELOG.md +25 -0
- package/LICENSE +21 -0
- package/README.md +993 -0
- package/dist/client.d.ts +2 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +5 -0
- package/dist/error.d.ts +3 -0
- package/dist/error.d.ts.map +1 -0
- package/dist/error.js +9 -0
- package/dist/{types/index.d.ts → index.d.ts} +2 -1
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/react.d.ts +3 -0
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +20 -0
- package/dist/{types/types/index.d.ts → types.d.ts} +132 -62
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/package.json +37 -29
- package/dist/cjs/client/index.js +0 -9
- package/dist/cjs/client/index.js.map +0 -1
- package/dist/cjs/client/initialize.js +0 -158
- package/dist/cjs/client/initialize.js.map +0 -1
- package/dist/cjs/index.js +0 -12
- package/dist/cjs/index.js.map +0 -1
- package/dist/cjs/utils/polyfillRequestAnimationFrame.js +0 -17
- package/dist/cjs/utils/polyfillRequestAnimationFrame.js.map +0 -1
- package/dist/esm/client/index.esm.js +0 -6
- package/dist/esm/client/index.esm.js.map +0 -1
- package/dist/esm/client/initialize.esm.js +0 -156
- package/dist/esm/client/initialize.esm.js.map +0 -1
- package/dist/esm/index.esm.js +0 -4
- package/dist/esm/index.esm.js.map +0 -1
- package/dist/esm/utils/polyfillRequestAnimationFrame.esm.js +0 -15
- package/dist/esm/utils/polyfillRequestAnimationFrame.esm.js.map +0 -1
- package/dist/mjs/client/index.mjs +0 -6
- package/dist/mjs/client/index.mjs.map +0 -1
- package/dist/mjs/client/initialize.mjs +0 -156
- package/dist/mjs/client/initialize.mjs.map +0 -1
- package/dist/mjs/index.mjs +0 -4
- package/dist/mjs/index.mjs.map +0 -1
- package/dist/mjs/utils/polyfillRequestAnimationFrame.mjs +0 -15
- package/dist/mjs/utils/polyfillRequestAnimationFrame.mjs.map +0 -1
- package/dist/types/.tsbuildinfo +0 -1
- package/dist/types/client/index.d.ts +0 -4
- package/dist/types/client/index.d.ts.map +0 -1
- package/dist/types/client/initialize.d.ts +0 -3
- package/dist/types/client/initialize.d.ts.map +0 -1
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/types/index.d.ts.map +0 -1
- package/dist/types/utils/polyfillRequestAnimationFrame.d.ts +0 -8
- package/dist/types/utils/polyfillRequestAnimationFrame.d.ts.map +0 -1
- package/dist/umd/plugin.development.js +0 -181
- package/dist/umd/plugin.development.js.map +0 -1
- package/dist/umd/plugin.production.min.js +0 -2
- package/dist/umd/plugin.production.min.js.map +0 -1
- package/src/client/index.ts +0 -5
- package/src/client/initialize.ts +0 -196
- package/src/globals.d.ts +0 -5
- package/src/index.ts +0 -4
- package/src/types/index.ts +0 -322
- package/src/utils/polyfillRequestAnimationFrame.ts +0 -13
package/README.md
ADDED
|
@@ -0,0 +1,993 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://github.com/sigmacomputing/plugin">
|
|
3
|
+
<picture>
|
|
4
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://github.com/sigmacomputing/plugin/blob/main/assets/sigma-logo-dark.svg">
|
|
5
|
+
<img alt="Sigma Logo" src="https://github.com/sigmacomputing/plugin/blob/main/assets/sigma-logo-light.svg" width="400px">
|
|
6
|
+
</picture>
|
|
7
|
+
</a>
|
|
8
|
+
</p>
|
|
9
|
+
|
|
10
|
+
Sigma Computing Plugins provides an API for third-party applications add
|
|
11
|
+
additional functionality into an existing Sigma workbook.
|
|
12
|
+
|
|
13
|
+
Plugins are built using Sigma’s Plugin API. This API communicates data and
|
|
14
|
+
interaction events between a Sigma workbook and the plugin. Plugins are hosted
|
|
15
|
+
by their developer and rendered in an iframe in Sigma.
|
|
16
|
+
|
|
17
|
+
#### Warning: Breaking Changes
|
|
18
|
+
|
|
19
|
+
`@sigmacomputing/plugin` has moved to https://github.com/sigmacomputing/plugin and
|
|
20
|
+
is now open source. Please read our
|
|
21
|
+
[CHANGELOG.md](https://github.com/sigmacomputing/plugin/blob/main/CHANGELOG.md)
|
|
22
|
+
to review any breaking changes that have been made.
|
|
23
|
+
|
|
24
|
+
## Requirements
|
|
25
|
+
|
|
26
|
+
To test your plugin in Sigma Plugin Dev Playground, you must:
|
|
27
|
+
|
|
28
|
+
- Have an Admin, Creator or Explorer account type
|
|
29
|
+
- Have Can Edit permission on the work
|
|
30
|
+
- Be in the workbook’s Edit mode
|
|
31
|
+
|
|
32
|
+
To test a development version of a registered plugin, you must:
|
|
33
|
+
|
|
34
|
+
- Have either:
|
|
35
|
+
|
|
36
|
+
- An Admin account type
|
|
37
|
+
- A custom account type that supports plugin developer feature permissions
|
|
38
|
+
|
|
39
|
+
- Have "can edit" permission on the workbook
|
|
40
|
+
- Be in the workbook’s Edit mode
|
|
41
|
+
|
|
42
|
+
Your plugin must be a Javascript-based project and run in the browser.
|
|
43
|
+
|
|
44
|
+
## Getting Started
|
|
45
|
+
|
|
46
|
+
### Installation
|
|
47
|
+
|
|
48
|
+
Provided you have already followed the steps to create a plugin and a plugin
|
|
49
|
+
development environment, you can install `@sigmacomputing/plugin` using one of
|
|
50
|
+
the following commands
|
|
51
|
+
|
|
52
|
+
```sh
|
|
53
|
+
yarn add @sigmacomputing/plugin
|
|
54
|
+
# or
|
|
55
|
+
npm install @sigmacomputing/plugin
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
If you have yet to set up your development environment, follow one of the setup
|
|
59
|
+
guides below
|
|
60
|
+
|
|
61
|
+
### Create a Development Project
|
|
62
|
+
|
|
63
|
+
At Sigma, we use React for all of our frontend development. This was taken into
|
|
64
|
+
consideration when building Sigma’s Plugin feature.
|
|
65
|
+
|
|
66
|
+
While you are not required to use React for your plugin, it must be written in
|
|
67
|
+
Javascript and React is recommended. We support both a standard Javascript API
|
|
68
|
+
and a React Hooks API.
|
|
69
|
+
|
|
70
|
+
#### Create a Project with Vite
|
|
71
|
+
|
|
72
|
+
1. Open your terminal and navigate to the directory you want to create your
|
|
73
|
+
project in.
|
|
74
|
+
2. Create your new project. We recommend using
|
|
75
|
+
[`create-vite`](https://www.npmjs.com/package/create-vite).
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
yarn create vite <my-cool-plugin>
|
|
79
|
+
# or
|
|
80
|
+
npm create vite@latest <my-cool-plugin>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
3. Then follow the prompts! You can also directly specify the project name and the template you want to use via additional command line options. For example, to scaffold a Vite + Vue project, run:
|
|
84
|
+
|
|
85
|
+
```sh
|
|
86
|
+
yarn create vite my-vue-app --template vue
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
4. Navigate to the project's main directory.
|
|
90
|
+
|
|
91
|
+
```sh
|
|
92
|
+
cd <my-cool-plugin>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
5. Use your package manager to install Sigma’s plugin library. We recommend
|
|
96
|
+
using `yarn`.
|
|
97
|
+
|
|
98
|
+
```sh
|
|
99
|
+
yarn add @sigmacomputing/plugin
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
6. Spin up your local development server.
|
|
103
|
+
|
|
104
|
+
```sh
|
|
105
|
+
yarn && yarn dev
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
7. Start developing:
|
|
109
|
+
|
|
110
|
+
- Get started with Sigma’s Plugin APIs.
|
|
111
|
+
- Test your plugin directly in a Sigma workbook using the Sigma Plugin Dev
|
|
112
|
+
Playground.
|
|
113
|
+
- By default, vite dev servers run on http://localhost:5173.
|
|
114
|
+
|
|
115
|
+
NOTE: Facebook's [create-react-app](https://github.com/facebook/create-react-app) is deprecated. You should use [vite](https://github.com/vitejs/vite) to setup your project.
|
|
116
|
+
|
|
117
|
+
## Testing your Plugin
|
|
118
|
+
|
|
119
|
+
Plugin developers should have access to a special plugin called Sigma Plugin Dev
|
|
120
|
+
Playground. This plugin is available from any workbook and points to
|
|
121
|
+
http://localhost:3000, by default.
|
|
122
|
+
|
|
123
|
+
If you cannot find this plugin, or would like a development playground with an
|
|
124
|
+
alternative default host, please contact your Organization Admin with a request
|
|
125
|
+
to Register a Plugin with its production URL set to your preferred development
|
|
126
|
+
URL.
|
|
127
|
+
|
|
128
|
+
### Using the Development Playground
|
|
129
|
+
|
|
130
|
+
Before you start:
|
|
131
|
+
|
|
132
|
+
- Set your plugin’s development URL to http://localhost:3000.
|
|
133
|
+
- Start your plugin locally
|
|
134
|
+
|
|
135
|
+
> Note: If you followed our recommendations under
|
|
136
|
+
> [#create-a-development-project](#create-a-development-project), enter the
|
|
137
|
+
> following command in your terminal:
|
|
138
|
+
>
|
|
139
|
+
> ```sh
|
|
140
|
+
> yarn && yarn start
|
|
141
|
+
> ```
|
|
142
|
+
|
|
143
|
+
1. Create/open a workbook.
|
|
144
|
+
2. In the workbook header, click Edit.
|
|
145
|
+
3. Click the + button in the sidebar, to open the workbook’s ADD NEW panel.
|
|
146
|
+
4. Select the PLUGINS element type, located under UI ELEMENTS.
|
|
147
|
+
5. The editor panel will show you a list of available plugins. Select Sigma
|
|
148
|
+
Plugin Dev Playground.
|
|
149
|
+
6. Your new plugin element will appear on the page.
|
|
150
|
+
|
|
151
|
+
> **Note:**
|
|
152
|
+
> The editor panel will only display content if you have configured your plugin
|
|
153
|
+
> using Sigma’s plugin [Configuration API](#documentation).
|
|
154
|
+
> Likewise, the element will only display content if your plugin is configured to display content.
|
|
155
|
+
> If you change a plugin's configuration options, input values will need to be
|
|
156
|
+
> re-added in the editor panel.
|
|
157
|
+
|
|
158
|
+
**Now what?**
|
|
159
|
+
|
|
160
|
+
- You can refresh your plugin as you make changes to its code. This option is
|
|
161
|
+
available from the element’s menu.
|
|
162
|
+
- You are responsible for hosting your plugin. [Learn more](#host-your-plugin).
|
|
163
|
+
- When you’re ready to register your plugin, [Add your custom your
|
|
164
|
+
Plugin](https://help.sigmacomputing.com/hc/en-us/articles/4410105794963) with
|
|
165
|
+
Sigma.
|
|
166
|
+
|
|
167
|
+
## Documentation
|
|
168
|
+
|
|
169
|
+
#### CustomPluginConfigOptions
|
|
170
|
+
|
|
171
|
+
A plugin can be configured with any number of configuration fields. Each field
|
|
172
|
+
type has its own configuration options. Each field type is also guaranteed to
|
|
173
|
+
have the following options:
|
|
174
|
+
|
|
175
|
+
- `name : string` - the name of the field
|
|
176
|
+
- `type : string` - the field type
|
|
177
|
+
- `label : string (optional)` - a display name for the field
|
|
178
|
+
|
|
179
|
+
<details>
|
|
180
|
+
<summary>Full CustomPluginConfigOptions Type</summary>
|
|
181
|
+
|
|
182
|
+
```ts
|
|
183
|
+
type CustomPluginConfigOptions =
|
|
184
|
+
| {
|
|
185
|
+
type: 'group';
|
|
186
|
+
name: string;
|
|
187
|
+
label?: string;
|
|
188
|
+
}
|
|
189
|
+
| {
|
|
190
|
+
type: 'element';
|
|
191
|
+
name: string;
|
|
192
|
+
label?: string;
|
|
193
|
+
}
|
|
194
|
+
| {
|
|
195
|
+
type: 'column';
|
|
196
|
+
name: string;
|
|
197
|
+
label?: string;
|
|
198
|
+
allowedTypes?: ValueType[];
|
|
199
|
+
source: string;
|
|
200
|
+
allowMultiple: boolean;
|
|
201
|
+
}
|
|
202
|
+
| {
|
|
203
|
+
type: 'text';
|
|
204
|
+
name: string;
|
|
205
|
+
label?: string;
|
|
206
|
+
source?: string; // can point to a group or element config
|
|
207
|
+
secure?: boolean; // if true will omit from prehydrated configs
|
|
208
|
+
multiline?: boolean;
|
|
209
|
+
placeholder?: string;
|
|
210
|
+
defaultValue?: string;
|
|
211
|
+
}
|
|
212
|
+
| {
|
|
213
|
+
type: 'toggle';
|
|
214
|
+
name: string;
|
|
215
|
+
label?: string;
|
|
216
|
+
source?: string;
|
|
217
|
+
defaultValue?: boolean;
|
|
218
|
+
}
|
|
219
|
+
| {
|
|
220
|
+
type: 'checkbox';
|
|
221
|
+
name: string;
|
|
222
|
+
label?: string;
|
|
223
|
+
source?: string;
|
|
224
|
+
defaultValue?: boolean;
|
|
225
|
+
}
|
|
226
|
+
| {
|
|
227
|
+
type: 'radio';
|
|
228
|
+
name: string;
|
|
229
|
+
label?: string;
|
|
230
|
+
source?: string;
|
|
231
|
+
values: string[];
|
|
232
|
+
singleLine?: boolean;
|
|
233
|
+
defaultValue?: string;
|
|
234
|
+
}
|
|
235
|
+
| {
|
|
236
|
+
type: 'dropdown';
|
|
237
|
+
name: string;
|
|
238
|
+
label?: string;
|
|
239
|
+
source?: string;
|
|
240
|
+
width?: string;
|
|
241
|
+
values: string[];
|
|
242
|
+
defaultValue?: string;
|
|
243
|
+
}
|
|
244
|
+
| {
|
|
245
|
+
type: 'color';
|
|
246
|
+
name: string;
|
|
247
|
+
label?: string;
|
|
248
|
+
source?: string;
|
|
249
|
+
}
|
|
250
|
+
| {
|
|
251
|
+
type: 'variable';
|
|
252
|
+
name: string;
|
|
253
|
+
label?: string;
|
|
254
|
+
allowedTypes?: ControlType[];
|
|
255
|
+
}
|
|
256
|
+
| {
|
|
257
|
+
type: 'interaction';
|
|
258
|
+
name: string;
|
|
259
|
+
label?: string;
|
|
260
|
+
}
|
|
261
|
+
| {
|
|
262
|
+
type: 'action-trigger';
|
|
263
|
+
name: string;
|
|
264
|
+
label?: string;
|
|
265
|
+
}
|
|
266
|
+
| {
|
|
267
|
+
type: 'action-effect';
|
|
268
|
+
name: string;
|
|
269
|
+
label?: string;
|
|
270
|
+
}
|
|
271
|
+
| {
|
|
272
|
+
type: 'url-parameter';
|
|
273
|
+
name: string;
|
|
274
|
+
};
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
</details>
|
|
278
|
+
|
|
279
|
+
**Group**
|
|
280
|
+
|
|
281
|
+
Can be used to identify a group of related fields
|
|
282
|
+
|
|
283
|
+
**Element**
|
|
284
|
+
|
|
285
|
+
A custom element that is added by your plugin
|
|
286
|
+
|
|
287
|
+
**Column**
|
|
288
|
+
|
|
289
|
+
A custom column configuration that your plugin uses
|
|
290
|
+
|
|
291
|
+
Additional Fields
|
|
292
|
+
|
|
293
|
+
- `allowedTypes : ValueType[] (optional)` - the allowed data types that this
|
|
294
|
+
column can contain where `ValueType` has the following type:
|
|
295
|
+
|
|
296
|
+
```ts
|
|
297
|
+
type ValueType =
|
|
298
|
+
| 'boolean'
|
|
299
|
+
| 'datetime'
|
|
300
|
+
| 'number'
|
|
301
|
+
| 'integer'
|
|
302
|
+
| 'text'
|
|
303
|
+
| 'variant'
|
|
304
|
+
| 'link'
|
|
305
|
+
| 'error';
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
- `source : string` - the data source that should be used to supply this field
|
|
309
|
+
- `allowMultiple : boolean` - whether multiple columns should be allowed as
|
|
310
|
+
input for this field
|
|
311
|
+
|
|
312
|
+
**Text**
|
|
313
|
+
|
|
314
|
+
A configurable text input for your plugin
|
|
315
|
+
|
|
316
|
+
Additional Fields
|
|
317
|
+
|
|
318
|
+
- `source : string (optional)` - the data source that should be used to supply this field
|
|
319
|
+
- `secure : boolean (optional)` - whether to omit input from pre-hydrated configs
|
|
320
|
+
- `multiline : boolean (optional)` - whether this text input should allow
|
|
321
|
+
multiple lines
|
|
322
|
+
- `placeholder : string (optional)` - the placeholder for this input field
|
|
323
|
+
- `defaultValue : string (optional)` - the default value for this input field
|
|
324
|
+
|
|
325
|
+
**Toggle**
|
|
326
|
+
|
|
327
|
+
A configurable toggle for your plugin
|
|
328
|
+
|
|
329
|
+
Additional Fields
|
|
330
|
+
|
|
331
|
+
- `source : string (optional)` - the data source that should be used to supply this field
|
|
332
|
+
- `defaultValue : boolean (optional)` - the default value for this input field
|
|
333
|
+
|
|
334
|
+
**Checkbox**
|
|
335
|
+
|
|
336
|
+
A configurable checkbox for your plugin
|
|
337
|
+
|
|
338
|
+
Additional Fields
|
|
339
|
+
|
|
340
|
+
- `source : string (optional)` - the data source that should be used to supply this field
|
|
341
|
+
- `defaultValue : boolean (optional)` - the default value for this input field
|
|
342
|
+
|
|
343
|
+
**Radio**
|
|
344
|
+
|
|
345
|
+
A configurable radio button for your plugin
|
|
346
|
+
|
|
347
|
+
Additional Fields
|
|
348
|
+
|
|
349
|
+
- `source : string (optional)` - the data source that should be used to supply
|
|
350
|
+
this field
|
|
351
|
+
- `values : string[]` - the options to show for this input field
|
|
352
|
+
- `singleLine : boolean (optional)` - whether to display options on a single
|
|
353
|
+
line. Good for (2-3) options
|
|
354
|
+
- `defaultValue : boolean (optional)` - the default value for this input field
|
|
355
|
+
|
|
356
|
+
**Dropdown**
|
|
357
|
+
|
|
358
|
+
A configurable dropdown for your plugin
|
|
359
|
+
|
|
360
|
+
Additional Fields
|
|
361
|
+
|
|
362
|
+
- `source : string (optional)` - the data source that should be used to supply
|
|
363
|
+
this field
|
|
364
|
+
- `values : string[]` - the options to show for this input field
|
|
365
|
+
- `width : string (optional)` - how wide the dropdown should be in pixels
|
|
366
|
+
- `defaultValue : boolean (optional)` - the default value for this input field
|
|
367
|
+
|
|
368
|
+
**Color**
|
|
369
|
+
|
|
370
|
+
A configurable color picker for your plugin
|
|
371
|
+
|
|
372
|
+
Additional Fields
|
|
373
|
+
|
|
374
|
+
- `source : string (optional)` - the data source that should be used to supply
|
|
375
|
+
this field
|
|
376
|
+
|
|
377
|
+
**Variable**
|
|
378
|
+
|
|
379
|
+
A configurable workbook variable to control other elements within your workbook
|
|
380
|
+
|
|
381
|
+
Additional Fields
|
|
382
|
+
|
|
383
|
+
- `allowedTypes : ControlType[] (optional)` - the allowed control types that this
|
|
384
|
+
variable can use where `ControlType` has the following type:
|
|
385
|
+
|
|
386
|
+
```ts
|
|
387
|
+
type ControlType =
|
|
388
|
+
| 'boolean'
|
|
389
|
+
| 'date'
|
|
390
|
+
| 'number'
|
|
391
|
+
| 'text'
|
|
392
|
+
| 'text-list'
|
|
393
|
+
| 'number-list'
|
|
394
|
+
| 'date-list'
|
|
395
|
+
| 'number-range'
|
|
396
|
+
| 'date-range';
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
**Interaction**
|
|
400
|
+
|
|
401
|
+
A configurable workbook interaction to interact with other charts within your workbook
|
|
402
|
+
|
|
403
|
+
**Action Trigger**
|
|
404
|
+
|
|
405
|
+
A configurable action trigger to trigger actions in other elements within your workbook
|
|
406
|
+
|
|
407
|
+
**Action Effect**
|
|
408
|
+
|
|
409
|
+
A configurable action effect that can be triggered by other elements within your workbook
|
|
410
|
+
|
|
411
|
+
**URL Parameter**
|
|
412
|
+
|
|
413
|
+
A configurable URL parameter that can be read from and written to the browser's URL. This allows plugins to sync state with the URL for bookmarking and sharing.
|
|
414
|
+
|
|
415
|
+
Additional Fields
|
|
416
|
+
|
|
417
|
+
- `name : string` - The config ID used to access this URL parameter via the API
|
|
418
|
+
|
|
419
|
+
#### PluginInstance
|
|
420
|
+
|
|
421
|
+
```ts
|
|
422
|
+
interface PluginInstance<T> {
|
|
423
|
+
sigmaEnv: 'author' | 'viewer' | 'explorer';
|
|
424
|
+
|
|
425
|
+
config: {
|
|
426
|
+
/**
|
|
427
|
+
* Getter for entire Plugin Config
|
|
428
|
+
*/
|
|
429
|
+
get(): Partial<T> | undefined;
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* Performs a shallow merge between current config and passed in config
|
|
433
|
+
*/
|
|
434
|
+
set(config: Partial<T>): void;
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Getter for key within plugin config
|
|
438
|
+
*/
|
|
439
|
+
getKey<K extends keyof T>(key: K): Pick<T, K>;
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Assigns key value pair within plugin
|
|
443
|
+
*/
|
|
444
|
+
setKey<K extends keyof T>(key: K, value: Pick<T, K>): void;
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Subscriber for Plugin Config
|
|
448
|
+
*/
|
|
449
|
+
subscribe(listener: (arg0: T) => void): Unsubscriber;
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Set possible options for plugin config
|
|
453
|
+
*/
|
|
454
|
+
configureEditorPanel(options: CustomPluginConfigOptions[]): void;
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Gets a static image of a workbook variable
|
|
458
|
+
*/
|
|
459
|
+
getVariable(configId: string): WorkbookVariable;
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* Setter for workbook variable passed in
|
|
463
|
+
*/
|
|
464
|
+
setVariable(configId: string, ...values: unknown[]): void;
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Getter for interaction selection state
|
|
468
|
+
*/
|
|
469
|
+
getInteraction(configId: string): WorkbookSelection[];
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Setter for interaction selection state
|
|
473
|
+
*/
|
|
474
|
+
setInteraction(
|
|
475
|
+
configId: string,
|
|
476
|
+
elementId: string,
|
|
477
|
+
selection: WorkbookSelection[],
|
|
478
|
+
): void;
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Triggers an action based on the provided action trigger ID
|
|
482
|
+
*/
|
|
483
|
+
triggerAction(configId: string): void;
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* Registers an effect with the provided action effect ID
|
|
487
|
+
*/
|
|
488
|
+
registerEffect(configId: string, effect: Function): void;
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Overrider function for Config Ready state
|
|
492
|
+
*/
|
|
493
|
+
setLoadingState(ready: boolean): void;
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* Allows users to subscribe to changes in the passed in variable
|
|
497
|
+
*/
|
|
498
|
+
subscribeToWorkbookVariable(
|
|
499
|
+
configId: string,
|
|
500
|
+
callback: (input: WorkbookVariable) => void,
|
|
501
|
+
): Unsubscriber;
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* Allows users to subscribe to changes in the url parameter
|
|
505
|
+
*/
|
|
506
|
+
subscribeToUrlParameter(
|
|
507
|
+
configId: string,
|
|
508
|
+
callback: (input: UrlParameter) => void,
|
|
509
|
+
): Unsubscriber;
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* Gets the current value of a url parameter
|
|
513
|
+
*/
|
|
514
|
+
getUrlParameter(configId: string): UrlParameter;
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Setter for url parameter
|
|
518
|
+
*/
|
|
519
|
+
setUrlParameter(configId: string, value: string): void;
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* @deprecated Use Action API instead
|
|
523
|
+
* Allows users to subscribe to changes in the passed in interaction ID
|
|
524
|
+
*/
|
|
525
|
+
subscribeToWorkbookInteraction(
|
|
526
|
+
configId: string,
|
|
527
|
+
callback: (input: WorkbookSelection[]) => void,
|
|
528
|
+
): Unsubscriber;
|
|
529
|
+
};
|
|
530
|
+
|
|
531
|
+
elements: {
|
|
532
|
+
/**
|
|
533
|
+
* Getter for Column Data by parent sheet ID
|
|
534
|
+
*/
|
|
535
|
+
getElementColumns(configId: string): Promise<WbElementColumns>;
|
|
536
|
+
|
|
537
|
+
/**
|
|
538
|
+
* Subscriber to changes in column data by ID
|
|
539
|
+
*/
|
|
540
|
+
subscribeToElementColumns(
|
|
541
|
+
configId: string,
|
|
542
|
+
callback: (cols: WbElementColumns) => void,
|
|
543
|
+
): Unsubscriber;
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Subscriber for the data within a given sheet
|
|
547
|
+
*/
|
|
548
|
+
subscribeToElementData(
|
|
549
|
+
configId: string,
|
|
550
|
+
callback: (data: WbElementData) => void,
|
|
551
|
+
): Unsubscriber;
|
|
552
|
+
};
|
|
553
|
+
|
|
554
|
+
style: {
|
|
555
|
+
/**
|
|
556
|
+
* Subscribe to workbook style updates
|
|
557
|
+
*/
|
|
558
|
+
subscribe(callback: (style: PluginStyle) => void): () => void;
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* Request current style from workbook
|
|
562
|
+
*/
|
|
563
|
+
get(): Promise<PluginStyle>;
|
|
564
|
+
};
|
|
565
|
+
|
|
566
|
+
/**
|
|
567
|
+
* Destroys plugin instance and removes all subscribers
|
|
568
|
+
*/
|
|
569
|
+
destroy(): void;
|
|
570
|
+
}
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
### Framework Agnostic API
|
|
574
|
+
|
|
575
|
+
#### client
|
|
576
|
+
|
|
577
|
+
The client is a pre-initialized plugin instance. You can use this instance
|
|
578
|
+
directly or create your own instance using `initialize`
|
|
579
|
+
|
|
580
|
+
```ts
|
|
581
|
+
const client: PluginInstance = initialize();
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
Usage
|
|
585
|
+
|
|
586
|
+
```ts
|
|
587
|
+
import { client } from '@sigmacomputing/plugin';
|
|
588
|
+
|
|
589
|
+
client.config.configureEditorPanel([
|
|
590
|
+
{ name: 'source', type: 'element' },
|
|
591
|
+
{ name: 'dimension', type: 'column', source: 'source', allowMultiple: true },
|
|
592
|
+
]);
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
#### initialize()
|
|
596
|
+
|
|
597
|
+
Instead of using the pre-initialized plugin instance, you can create your own
|
|
598
|
+
plugin instance.
|
|
599
|
+
|
|
600
|
+
```ts
|
|
601
|
+
function initialize<T = {}>(): PluginInstance<T>;
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
Usage
|
|
605
|
+
|
|
606
|
+
```ts
|
|
607
|
+
import { initialize } from '@sigmacomputing/plugin';
|
|
608
|
+
|
|
609
|
+
const myClient: PluginInstance = initialize();
|
|
610
|
+
|
|
611
|
+
myClient.config.configureEditorPanel([
|
|
612
|
+
{ name: 'source', type: 'element' },
|
|
613
|
+
{ name: 'dimension', type: 'column', source: 'source', allowMultiple: true },
|
|
614
|
+
]);
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
### React API
|
|
618
|
+
|
|
619
|
+
#### <SigmaClientProvider />
|
|
620
|
+
|
|
621
|
+
A context provider your plugin that enables all of the other React API hooks.
|
|
622
|
+
You should wrap your plugin with this provider if your want to use the plugin
|
|
623
|
+
hook API.
|
|
624
|
+
|
|
625
|
+
```ts
|
|
626
|
+
interface SigmaClientProviderProps {
|
|
627
|
+
client: PluginInstance;
|
|
628
|
+
children?: ReactNode;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
function SigmaClientProvider(props: SigmaClientProviderProps): ReactNode;
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
#### usePlugin()
|
|
635
|
+
|
|
636
|
+
Gets the entire plugin instance
|
|
637
|
+
|
|
638
|
+
```ts
|
|
639
|
+
function usePlugin(): PluginInstance;
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
#### useEditorPanelConfig()
|
|
643
|
+
|
|
644
|
+
Provides a setter for the plugin's configuration options
|
|
645
|
+
|
|
646
|
+
```ts
|
|
647
|
+
function useEditorPanelConfig(nextOptions: CustomPluginConfigOptions[]): void;
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
Provides a setter for the Plugin's Config Options
|
|
651
|
+
|
|
652
|
+
Arguments
|
|
653
|
+
|
|
654
|
+
- `nextOptions : CustomPluginConfigOptions[]` - Updated possible Config Options
|
|
655
|
+
|
|
656
|
+
#### useLoadingState()
|
|
657
|
+
|
|
658
|
+
Gets the current plugin's loading stat. Returns a value and a setter allowing
|
|
659
|
+
you to update the plugin's loading state
|
|
660
|
+
|
|
661
|
+
```ts
|
|
662
|
+
function useLoadingState(
|
|
663
|
+
initialState: boolean,
|
|
664
|
+
): [boolean, (nextState: boolean) => void];
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
Arguments
|
|
668
|
+
|
|
669
|
+
- `initialState : boolean` - Initial value to set loading state to
|
|
670
|
+
|
|
671
|
+
#### useElementColumns()
|
|
672
|
+
|
|
673
|
+
Provides the latest column values from corresponding sheet
|
|
674
|
+
|
|
675
|
+
```ts
|
|
676
|
+
function useElementColumns(elementId: string): WorkbookElementColumns;
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
Arguments
|
|
680
|
+
|
|
681
|
+
- `elementId : string` - A workbook element’s unique identifier.
|
|
682
|
+
|
|
683
|
+
Returns the column information from the specified element.
|
|
684
|
+
|
|
685
|
+
```ts
|
|
686
|
+
interface WorkbookElementColumn {
|
|
687
|
+
id: string;
|
|
688
|
+
name: string;
|
|
689
|
+
columnType: ValueType;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
interface WorkbookElementColumns {
|
|
693
|
+
[colId: string]: WbElementColumn;
|
|
694
|
+
}
|
|
695
|
+
```
|
|
696
|
+
|
|
697
|
+
#### useElementData()
|
|
698
|
+
|
|
699
|
+
Provides the latest data values from corresponding sheet, up to 25000 values.
|
|
700
|
+
|
|
701
|
+
```ts
|
|
702
|
+
function useElementData(configId: string): WorkbookElementData;
|
|
703
|
+
```
|
|
704
|
+
|
|
705
|
+
Arguments
|
|
706
|
+
|
|
707
|
+
- `configId : string` - A workbook element’s unique identifier from the plugin config.
|
|
708
|
+
|
|
709
|
+
Returns the row data from the specified element.
|
|
710
|
+
|
|
711
|
+
```ts
|
|
712
|
+
interface WorkbookElementData {
|
|
713
|
+
[colId: string]: any[];
|
|
714
|
+
}
|
|
715
|
+
```
|
|
716
|
+
|
|
717
|
+
#### usePaginatedElementData()
|
|
718
|
+
|
|
719
|
+
Provides the latest data values from the corresponding sheet (initially 25000), and provides a
|
|
720
|
+
callback for fetching more data in chunks of 25000 values.
|
|
721
|
+
|
|
722
|
+
```ts
|
|
723
|
+
function useElementData(configId: string): [WorkbookElementData, () => void];
|
|
724
|
+
```
|
|
725
|
+
|
|
726
|
+
Arguments
|
|
727
|
+
|
|
728
|
+
- `configId : string` - A workbook element’s unique identifier from the plugin config.
|
|
729
|
+
|
|
730
|
+
Returns the row data from the specified element, and a callback for fetching
|
|
731
|
+
more data.
|
|
732
|
+
|
|
733
|
+
```ts
|
|
734
|
+
interface WorkbookElementData {
|
|
735
|
+
[colId: string]: any[];
|
|
736
|
+
}
|
|
737
|
+
```
|
|
738
|
+
|
|
739
|
+
#### useVariable()
|
|
740
|
+
|
|
741
|
+
Returns a given variable's value and a setter to update that variable
|
|
742
|
+
|
|
743
|
+
```ts
|
|
744
|
+
function useVariable(
|
|
745
|
+
configId: string,
|
|
746
|
+
): [WorkbookVariable | undefined, (...values: unknown[]) => void];
|
|
747
|
+
```
|
|
748
|
+
|
|
749
|
+
Arguments
|
|
750
|
+
|
|
751
|
+
- `configId : string` - The config ID corresponding to the workbook control variable
|
|
752
|
+
|
|
753
|
+
The returned setter function accepts 1 or more variable values expressed as an
|
|
754
|
+
array or multiple parameters
|
|
755
|
+
|
|
756
|
+
```ts
|
|
757
|
+
function setVariableCallback(...values: unknown[]): void;
|
|
758
|
+
```
|
|
759
|
+
|
|
760
|
+
#### useUrlParameter()
|
|
761
|
+
|
|
762
|
+
Returns a given URL parameter's value and a setter to update that URL parameter
|
|
763
|
+
|
|
764
|
+
```ts
|
|
765
|
+
function useUrlParameter(
|
|
766
|
+
configId: string,
|
|
767
|
+
): [UrlParameter | undefined, (value: string) => void];
|
|
768
|
+
```
|
|
769
|
+
|
|
770
|
+
Arguments
|
|
771
|
+
|
|
772
|
+
- `configId : string` - The config ID corresponding to the URL parameter
|
|
773
|
+
|
|
774
|
+
The returned setter function accepts a string value that will be set as the URL parameter value
|
|
775
|
+
|
|
776
|
+
```ts
|
|
777
|
+
function setUrlParameterCallback(value: string): void;
|
|
778
|
+
```
|
|
779
|
+
|
|
780
|
+
The URL parameter value has the following structure:
|
|
781
|
+
|
|
782
|
+
```ts
|
|
783
|
+
interface UrlParameter {
|
|
784
|
+
value: string;
|
|
785
|
+
}
|
|
786
|
+
```
|
|
787
|
+
|
|
788
|
+
Example
|
|
789
|
+
|
|
790
|
+
```ts
|
|
791
|
+
const [urlParam, setUrlParam] = useUrlParameter('myParamId');
|
|
792
|
+
|
|
793
|
+
// Read the current value
|
|
794
|
+
console.log(urlParam?.value); // e.g., "current-value"
|
|
795
|
+
|
|
796
|
+
// Update the URL parameter
|
|
797
|
+
setUrlParam('new-value');
|
|
798
|
+
```
|
|
799
|
+
|
|
800
|
+
Framework Agnostic Usage
|
|
801
|
+
|
|
802
|
+
You can also use the URL parameter API without React hooks:
|
|
803
|
+
|
|
804
|
+
```ts
|
|
805
|
+
import { initialize } from '@sigmacomputing/plugin';
|
|
806
|
+
|
|
807
|
+
const client = initialize();
|
|
808
|
+
|
|
809
|
+
// Get current value
|
|
810
|
+
const urlParam = client.config.getUrlParameter('myParamId');
|
|
811
|
+
console.log(urlParam?.value);
|
|
812
|
+
|
|
813
|
+
// Set a new value
|
|
814
|
+
client.config.setUrlParameter('myParamId', 'new-value');
|
|
815
|
+
|
|
816
|
+
// Subscribe to changes
|
|
817
|
+
const unsubscribe = client.config.subscribeToUrlParameter('myParamId', (urlParam) => {
|
|
818
|
+
console.log('URL parameter updated:', urlParam.value);
|
|
819
|
+
});
|
|
820
|
+
```
|
|
821
|
+
|
|
822
|
+
#### useInteraction()
|
|
823
|
+
|
|
824
|
+
Returns a given interaction's selection state and a setter to update that interaction
|
|
825
|
+
|
|
826
|
+
```ts
|
|
827
|
+
function useInteraction(
|
|
828
|
+
configId: string,
|
|
829
|
+
elementId: string,
|
|
830
|
+
): [WorkbookSelection | undefined, (value: WorkbookSelection[]) => void];
|
|
831
|
+
```
|
|
832
|
+
|
|
833
|
+
Arguments
|
|
834
|
+
|
|
835
|
+
- `configId : string` - The config ID corresponding to the workbook interaction
|
|
836
|
+
- `elementId : string` - The ID of the element that this interaction is
|
|
837
|
+
associated with
|
|
838
|
+
|
|
839
|
+
The returned setter function accepts an array of workbook selection elements
|
|
840
|
+
|
|
841
|
+
```ts
|
|
842
|
+
function setVariableCallback(value: WorkbookSelection[]): void;
|
|
843
|
+
```
|
|
844
|
+
|
|
845
|
+
#### useActionTrigger()
|
|
846
|
+
|
|
847
|
+
- `configId : string` - The config ID corresponding to the action trigger
|
|
848
|
+
|
|
849
|
+
Returns a callback function to trigger one or more action effects for a given action trigger
|
|
850
|
+
|
|
851
|
+
```ts
|
|
852
|
+
function useActionTrigger(configId: string): () => void;
|
|
853
|
+
```
|
|
854
|
+
|
|
855
|
+
#### useActionEffect()
|
|
856
|
+
|
|
857
|
+
Registers and unregisters an action effect within the plugin
|
|
858
|
+
|
|
859
|
+
```ts
|
|
860
|
+
function useActionEffect(configId: string, effect: () => void);
|
|
861
|
+
```
|
|
862
|
+
|
|
863
|
+
Arguments
|
|
864
|
+
|
|
865
|
+
- `configId : string` - The config ID corresponding to the action effect
|
|
866
|
+
- `effect : Function` - The function to be called when the effect is triggered
|
|
867
|
+
|
|
868
|
+
#### usePluginStyle()
|
|
869
|
+
|
|
870
|
+
Returns style properties from the workbook.
|
|
871
|
+
|
|
872
|
+
```ts
|
|
873
|
+
function usePluginStyle(): PluginStyle | undefined;
|
|
874
|
+
```
|
|
875
|
+
|
|
876
|
+
> **Note:** Currently, the `PluginStyle` interface only supports the `backgroundColor` property, which reflects the background color set in the workbook for the plugin element.
|
|
877
|
+
|
|
878
|
+
#### useConfig()
|
|
879
|
+
|
|
880
|
+
Returns the workbook element’s current configuration. If a key is provided, only
|
|
881
|
+
the associated configuration is returned.
|
|
882
|
+
|
|
883
|
+
```ts
|
|
884
|
+
function useConfig(key?: string): any;
|
|
885
|
+
```
|
|
886
|
+
|
|
887
|
+
Arguments
|
|
888
|
+
|
|
889
|
+
- `key : string (optional)` - The name of a key within the associated
|
|
890
|
+
`PluginConfigOptions` object
|
|
891
|
+
|
|
892
|
+
## Examples
|
|
893
|
+
|
|
894
|
+
Sigma’s development team has created a set of example plugins, listed below.
|
|
895
|
+
|
|
896
|
+
All of our example plugins are hosted and can be added to your organization. To
|
|
897
|
+
view / add an example plugin to your organization, follow the steps to register
|
|
898
|
+
a plugin using its Production URL, listed below.
|
|
899
|
+
|
|
900
|
+
You can also visit Sigma’s [Sample Plugin
|
|
901
|
+
repository](https://github.com/sigmacomputing/sigma-sample-plugins) directly on
|
|
902
|
+
Github.
|
|
903
|
+
|
|
904
|
+
### Available Plugins
|
|
905
|
+
|
|
906
|
+
- **Recharts Bar Chart** - A basic bar chart built with the Recharts library.
|
|
907
|
+
|
|
908
|
+
- [Source Code](https://github.com/sigmacomputing/sigma-sample-plugins/tree/main/sample-plugin-bar-chart)
|
|
909
|
+
- Production URL: https://sigma-sample-bar-chart-54049.netlify.app/
|
|
910
|
+
|
|
911
|
+
- **D3 Candlestick** - A candlestick visualization built with D3.
|
|
912
|
+
|
|
913
|
+
- [Source Code](https://github.com/sigmacomputing/sigma-sample-plugins/tree/main/sample-plugin-bar-chart)
|
|
914
|
+
- Production URL: https://sigma-sample-candlestick-chart-1664e5.netlify.app/
|
|
915
|
+
|
|
916
|
+
- **Narrative Science Quill** - Demonstrates secure text entry.
|
|
917
|
+
|
|
918
|
+
- [Source Code]()
|
|
919
|
+
- Production URL: https://narrativescience-quill-3ee312.netlify.app/
|
|
920
|
+
|
|
921
|
+
- **D3 Graph** - Demonstrates usage of multiple data sources and in-memory
|
|
922
|
+
joins.
|
|
923
|
+
|
|
924
|
+
- [Source Code](https://github.com/sigmacomputing/sigma-sample-plugins/tree/main/d3-graph)
|
|
925
|
+
- Production URL: https://d3-graph-3a0d0f.netlify.app/
|
|
926
|
+
|
|
927
|
+
- **D3 Sunburst** - A sunburst visualization built with D3.
|
|
928
|
+
|
|
929
|
+
- [Source Code](https://github.com/sigmacomputing/sigma-sample-plugins/tree/main/d3-sunburst)
|
|
930
|
+
- Production URL: https://d3-sunburst-b97c7c.netlify.app/
|
|
931
|
+
|
|
932
|
+
- **Frappe Heatmap** - A basic Frappe visualization example.
|
|
933
|
+
|
|
934
|
+
- [Source Code](https://github.com/sigmacomputing/sigma-sample-plugins/tree/main/frappe-heatmap)
|
|
935
|
+
- Production URL: https://frappe-heatmap-9a4163.netlify.app/
|
|
936
|
+
|
|
937
|
+
### Use an Example in Your Organization
|
|
938
|
+
|
|
939
|
+
To add an example plugin to your organization, follow the steps to [register a
|
|
940
|
+
plugin](https://help.sigmacomputing.com/hc/en-us/articles/4410105794963) using
|
|
941
|
+
its Production URL, listed in the [examples](#available-plugins) above.
|
|
942
|
+
|
|
943
|
+
### Run an Example Locally
|
|
944
|
+
|
|
945
|
+
1. Open your terminal, and navigate to the directory you want to save the example’s in.
|
|
946
|
+
2. Clone Sigma’s [Sample Plugin
|
|
947
|
+
repository](https://github.com/sigmacomputing/sigma-sample-plugins).
|
|
948
|
+
|
|
949
|
+
```sh
|
|
950
|
+
git clone https://github.com/sigmacomputing/sigma-sample-plugins.git
|
|
951
|
+
```
|
|
952
|
+
|
|
953
|
+
3. Navigate to the plugin you would like to try.
|
|
954
|
+
|
|
955
|
+
```sh
|
|
956
|
+
cd sigma-sample-plugins/<plugin-name>
|
|
957
|
+
```
|
|
958
|
+
|
|
959
|
+
4. Run the plugin.
|
|
960
|
+
|
|
961
|
+
```sh
|
|
962
|
+
yarn && yarn start
|
|
963
|
+
```
|
|
964
|
+
|
|
965
|
+
> **Note**: For additional instructions, visit the README file located in the main directory of any given example plugin.
|
|
966
|
+
|
|
967
|
+
## Host Your Plugin
|
|
968
|
+
|
|
969
|
+
As a plugin developer, you are responsible for hosting your plugin(s). If you’re
|
|
970
|
+
new to hosting your own projects, here are a few popular hosting platforms you
|
|
971
|
+
can get started with:
|
|
972
|
+
|
|
973
|
+
- [Heroku](https://devcenter.heroku.com/)
|
|
974
|
+
- [Netlify](https://www.netlify.com/)
|
|
975
|
+
|
|
976
|
+
## Contributing
|
|
977
|
+
|
|
978
|
+
We welcome contributions to `@sigmacomputing/plugin`!
|
|
979
|
+
|
|
980
|
+
🐛 Issues, 📥 Pull requests and 🌟 Stars are always welcome.
|
|
981
|
+
Read our [contributing
|
|
982
|
+
guide](https://github.com/sigmacomputing/plugin/blob/main/CONTRIBUTING.md) to
|
|
983
|
+
get started.
|
|
984
|
+
|
|
985
|
+
**yarn format**
|
|
986
|
+
|
|
987
|
+
Format your code to match the sigmacomputing style guide
|
|
988
|
+
|
|
989
|
+
**yarn test**
|
|
990
|
+
|
|
991
|
+
Check if the unit tests all pass
|
|
992
|
+
|
|
993
|
+
> You can also run the tests in `--watch` mode with **yarn test:watch**
|