Skip to content

Commit d35a765

Browse files
authored
Add URL parameter support (#33)
1 parent 87f84bd commit d35a765

File tree

5 files changed

+193
-5
lines changed

5 files changed

+193
-5
lines changed

.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: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,14 @@ export interface WorkbookVariable {
4242
defaultValue: { type: string };
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<{
@@ -185,6 +193,10 @@ export type CustomPluginConfigOptions =
185193
type: 'action-effect';
186194
name: string;
187195
label?: string;
196+
}
197+
| {
198+
type: 'url-parameter',
199+
name: string
188200
};
189201

190202
/**
@@ -307,6 +319,31 @@ export interface PluginInstance<T = any> {
307319
callback: (input: WorkbookVariable) => void,
308320
): Unsubscriber;
309321

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

0 commit comments

Comments
 (0)