Skip to content

Commit 2492fc9

Browse files
Merge branch 'main' into peter/fan-out-config-option-types
2 parents 495807f + d35a765 commit 2492fc9

5 files changed

Lines changed: 196 additions & 6 deletions

File tree

.nvmrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
v18.16.1
1+
v20.17.0

README.md

Lines changed: 96 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -264,10 +264,14 @@ type CustomPluginConfigOptions =
264264
label?: string;
265265
}
266266
| {
267-
type: 'action-effect';
268-
name: string;
269-
label?: string;
270-
};
267+
type: 'action-effect';
268+
name: string;
269+
label?: string;
270+
}
271+
| {
272+
type: 'url-parameter';
273+
name: string;
274+
};
271275
```
272276
273277
</details>
@@ -404,6 +408,14 @@ A configurable action trigger to trigger actions in other elements within your w
404408
405409
A configurable action effect that can be triggered by other elements within your workbook
406410
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+
407419
#### PluginInstance
408420
409421
```ts
@@ -488,6 +500,24 @@ interface PluginInstance<T> {
488500
callback: (input: WorkbookVariable) => void,
489501
): Unsubscriber;
490502
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+
491521
/**
492522
* @deprecated Use Action API instead
493523
* Allows users to subscribe to changes in the passed in interaction ID
@@ -727,6 +757,68 @@ array or multiple parameters
727757
function setVariableCallback(...values: unknown[]): void;
728758
```
729759
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+
730822
#### useInteraction()
731823
732824
Returns a given interaction's selection state and a setter to update that interaction

src/client/initialize.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
PluginInstance,
55
PluginMessageResponse,
66
PluginStyle,
7+
UrlParameter,
78
WorkbookSelection,
89
WorkbookVariable,
910
} from '../types';
@@ -15,6 +16,7 @@ export function initialize<T = {}>(): PluginInstance<T> {
1516

1617
let subscribedInteractions: Record<string, WorkbookSelection[]> = {};
1718
let subscribedWorkbookVars: Record<string, WorkbookVariable> = {};
19+
let subscribedUrlParameters: Record<string, UrlParameter> = {};
1820
const registeredEffects: Record<string, () => void> = {};
1921

2022
const listeners: {
@@ -61,6 +63,14 @@ export function initialize<T = {}>(): PluginInstance<T> {
6163
Object.assign(subscribedInteractions, updatedInteractions);
6264
});
6365

66+
on(
67+
'wb:plugin:url-parameter:update',
68+
(updatedUrlParameters: Record<string, UrlParameter>) => {
69+
subscribedUrlParameters = {};
70+
Object.assign(subscribedUrlParameters, updatedUrlParameters);
71+
},
72+
);
73+
6474
on('wb:plugin:action-effect:invoke', (configId: string) => {
6575
const effect = registeredEffects[configId];
6676
if (!effect) {
@@ -191,6 +201,25 @@ export function initialize<T = {}>(): PluginInstance<T> {
191201
off('wb:plugin:selection:update', setValues);
192202
};
193203
},
204+
subscribeToUrlParameter(configId, callback) {
205+
validateConfigId(configId, 'url-parameter');
206+
const setValues = (values: Record<string, UrlParameter>) => {
207+
callback(values[configId]);
208+
};
209+
setValues(subscribedUrlParameters);
210+
on('wb:plugin:url-parameter:update', setValues);
211+
return () => {
212+
off('wb:plugin:url-parameter:update', setValues);
213+
};
214+
},
215+
getUrlParameter(configId: string) {
216+
validateConfigId(configId, 'url-parameter');
217+
return subscribedUrlParameters[configId];
218+
},
219+
setUrlParameter(configId: string, value: string) {
220+
validateConfigId(configId, 'url-parameter');
221+
void execPromise('wb:plugin:url-parameter:set', configId, value);
222+
}
194223
},
195224
elements: {
196225
getElementColumns(configId) {

src/react/hooks.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
WorkbookSelection,
1010
WorkbookVariable,
1111
PluginStyle,
12+
UrlParameter,
1213
} from '../types';
1314
import { deepEqual } from '../utils/deepEqual';
1415

@@ -184,6 +185,35 @@ export function useVariable(
184185
return [workbookVariable, setVariable];
185186
}
186187

188+
/**
189+
* React hook for accessing a url parameter
190+
* @param {string} id ID from the config of type: 'url-parameter'
191+
* @returns {[(UrlParameter | undefined), Function]} Constantly updating value of the url parameter and setter for the url parameter
192+
*/
193+
export function useUrlParameter(
194+
id: string
195+
): [UrlParameter | undefined, (value: string) => void] {
196+
const client = usePlugin();
197+
const [urlParameter, setUrlParameter] = useState<UrlParameter>();
198+
199+
const isFirstRender = useRef<boolean>(true);
200+
201+
useEffect(() => {
202+
if (isFirstRender.current) {
203+
setUrlParameter(client.config.getUrlParameter(id));
204+
isFirstRender.current = false;
205+
}
206+
return client.config.subscribeToUrlParameter(id, setUrlParameter);
207+
}, [client, id]);
208+
209+
const setter = useCallback(
210+
(value: string) => client.config.setUrlParameter(id, value),
211+
[client, id],
212+
);
213+
214+
return [urlParameter, setter];
215+
}
216+
187217
/**
188218
* @deprecated Use Action API instead
189219
* React hook for accessing a workbook interaction selections state

src/types.ts

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,14 @@ export interface WorkbookVariable {
4242
defaultValue: { type: string; value: any };
4343
}
4444

45+
/**
46+
* @typedef {object} UrlParameter
47+
* @property {string} value Current url value
48+
*/
49+
export interface UrlParameter {
50+
value: string;
51+
}
52+
4553
export type WorkbookSelection = Record<string, { type: string; val?: unknown }>;
4654

4755
export type PluginMessageResponse = MessageEvent<{
@@ -163,6 +171,11 @@ export interface CustomPluginConfigActionEffect
163171
extends CustomPluginConfigOptionBase {
164172
type: 'action-effect';
165173
}
174+
export interface CustomPluginConfigUrlParameter
175+
extends Omit<CustomPluginConfigOptionBase, 'label'> {
176+
type: 'url-parameter',
177+
name: string
178+
}
166179

167180
/**
168181
* Different types Plugin Config Options
@@ -184,7 +197,8 @@ export type CustomPluginConfigOptions =
184197
| CustomPluginConfigVariable
185198
| CustomPluginConfigInteraction
186199
| CustomPluginConfigActionTrigger
187-
| CustomPluginConfigActionEffect;
200+
| CustomPluginConfigActionEffect
201+
| CustomPluginConfigUrlParameter;
188202

189203
/**
190204
* @typedef {object} PluginInstance
@@ -306,6 +320,31 @@ export interface PluginInstance<T = any> {
306320
callback: (input: WorkbookVariable) => void,
307321
): Unsubscriber;
308322

323+
/**
324+
* Allows users to subscribe to changes in the url parameter
325+
* @param {string} configId ID from config of type: 'url-parameter'
326+
* @callback callback Function to be called upon receiving an updated url parameter
327+
* @returns {Unsubscriber} A callable unsubscriber
328+
*/
329+
subscribeToUrlParameter(
330+
configId: string,
331+
callback: (input: UrlParameter) => void,
332+
): Unsubscriber;
333+
334+
/**
335+
* Gets the current value of a url parameter
336+
* @param {string} configId ID from config of type: 'url-parameter'
337+
* @returns {UrlParameter} Current value of the url parameter
338+
*/
339+
getUrlParameter(configId: string): UrlParameter;
340+
341+
/**
342+
* Setter for url parameter
343+
* @param {string} configId ID from config of type: 'url-parameter'
344+
* @param {string} value Value to assign to the url parameter
345+
*/
346+
setUrlParameter(configId: string, value: string): void;
347+
309348
/**
310349
* @deprecated Use Action API instead
311350
* Allows users to subscribe to changes in the passed in interaction ID

0 commit comments

Comments
 (0)