Skip to content

Commit dcab78f

Browse files
committed
[manager] Destructure scheduleTestRun
1 parent bc1e59b commit dcab78f

File tree

9 files changed

+325
-33
lines changed

9 files changed

+325
-33
lines changed

src/@types/docs.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -959,6 +959,35 @@
959959
* @since v1.0.0
960960
*/
961961
/// Manager.scheduleTaskRun
962+
/**
963+
* When called with an object as the first argument, the scheduleTaskRun
964+
* method destructures it to make it easier to skip optional parameters.
965+
* @param args An object containing the Id of the task to run, an optional
966+
* string argument to pass to the Task, an optional timestamp at, or duration
967+
* after which, the task should run; and an optional TaskRunConfig to set for
968+
* this run.
969+
* @returns A new unique Id of the scheduled task run, or `undefined` if
970+
* unsuccessful.
971+
* @example
972+
* This example registers a task that is then scheduled to run.
973+
*
974+
* ```js
975+
* import {createManager} from 'tinytick';
976+
*
977+
* const manager = createManager();
978+
* manager.setTask('ping', async () => await fetch('https://example.org'));
979+
*
980+
* const taskRunId = manager.scheduleTaskRun({taskId: 'ping', startAfter: 1});
981+
* console.log(manager.getScheduledTaskRunIds().length);
982+
* // -> 1
983+
*
984+
* console.log(manager.getTaskRunInfo(taskRunId).taskId);
985+
* // -> 'ping'
986+
* ```
987+
* @category TaskRun
988+
* @since v1.2.5
989+
*/
990+
/// Manager.scheduleTaskRun.2
962991
/**
963992
* The getTaskRunConfig method returns the configuration of a task run.
964993
*

src/@types/index.d.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,14 @@ export interface Manager {
195195
config?: TaskRunConfig,
196196
): Id | undefined;
197197

198+
/// Manager.scheduleTaskRun.2
199+
scheduleTaskRun(args: {
200+
taskId: Id;
201+
arg?: string;
202+
startAfter?: TimestampMs | DurationMs;
203+
config?: TaskRunConfig;
204+
}): Id | undefined;
205+
198206
/// Manager.getTaskRunConfig
199207
getTaskRunConfig<WithDefaults extends boolean>(
200208
taskRunId: Id,

src/@types/ui-react/docs.js

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,53 @@
582582
* @since v1.2.1
583583
*/
584584
/// useScheduleTaskRun
585+
/**
586+
* When called with an object as the first argument, the useScheduleTaskRun
587+
* hook destructures it to make it easier to skip optional parameters.
588+
* @param args An object containing the Id of the task to run, an optional
589+
* string argument to pass to the Task, an optional timestamp at, or duration
590+
* after which, the task should run; and an optional TaskRunConfig to set for
591+
* this run.
592+
* @param configDeps An optional array of dependencies for the config object,
593+
* which, if any change, result in the task being scheduled again. Defaults to
594+
* an empty array.
595+
* @returns The new unique Id of the scheduled task run, or `undefined` if
596+
* unsuccessful.
597+
* @example
598+
* This example shows how to use the useScheduleTaskRun hook within a
599+
* component that's nested inside a Provider. The hook is used to create a
600+
* callback that will schedule a task in response to a click event.
601+
*
602+
* ```jsx
603+
* import React from 'react';
604+
* import {createRoot} from 'react-dom/client';
605+
* import {createManager} from 'tinytick';
606+
* import {Provider, useScheduleTaskRun} from 'tinytick/ui-react';
607+
*
608+
* const Pane = () => {
609+
* useScheduleTaskRun({taskId: 'log'});
610+
* return null;
611+
* };
612+
* const App = ({manager}) => (
613+
* <Provider manager={manager}>
614+
* <Pane />
615+
* </Provider>
616+
* );
617+
*
618+
* const manager = createManager().start();
619+
* manager.setTask('log', async () => console.log('Task ran'));
620+
*
621+
* const app = document.createElement('div');
622+
* const root = createRoot(app);
623+
* root.render(<App manager={manager} />); // !act
624+
*
625+
* // ... wait 100ms for task to start running // !act
626+
* // -> 'Task ran'
627+
* ```
628+
* @category Task run hooks
629+
* @since v1.2.5
630+
*/
631+
/// useScheduleTaskRun.2
585632

586633
/**
587634
* The useScheduleTaskRunCallback hook returns a function that can be used to
@@ -653,6 +700,65 @@
653700
* @since v1.2.0
654701
*/
655702
/// useScheduleTaskRunCallback
703+
/**
704+
* When called with an object as the first argument, the
705+
* useScheduleTaskRunCallback hook destructures it to make it easier to skip
706+
* optional parameters.
707+
* @param args An object containing the Id of the task to run, an optional
708+
* string argument to pass to the Task, an optional timestamp at, or duration
709+
* after which, the task should run; and an optional TaskRunConfig to set for
710+
* this run.
711+
* @param configDeps An optional array of dependencies for the config object,
712+
* which, if any change, result in the callback being regenerated. Defaults to
713+
* an empty array.
714+
* @returns A callback that will return the new unique Id of the scheduled task
715+
* run, or `undefined` if unsuccessful.
716+
* @example
717+
* This example shows how to use the useScheduleTaskRunCallback hook within a
718+
* component that's nested inside a Provider. The hook is used to create a
719+
* callback that will schedule a task in response to a click event.
720+
*
721+
* ```jsx
722+
* import React from 'react';
723+
* import {createRoot} from 'react-dom/client';
724+
* import {createManager} from 'tinytick';
725+
* import {Provider, useScheduleTaskRunCallback} from 'tinytick/ui-react';
726+
*
727+
* const Pane = () => {
728+
* const handleClick = useScheduleTaskRunCallback({taskId: 'log'});
729+
* return (
730+
* <span id="span" onClick={handleClick}>
731+
* Log
732+
* </span>
733+
* );
734+
* };
735+
* const App = ({manager}) => (
736+
* <Provider manager={manager}>
737+
* <Pane />
738+
* </Provider>
739+
* );
740+
*
741+
* const manager = createManager().start();
742+
* manager.setTask('log', async () => console.log('Task ran'));
743+
*
744+
* const app = document.createElement('div');
745+
* const root = createRoot(app);
746+
* root.render(<App manager={manager} />); // !act
747+
* const span = app.querySelector('span');
748+
*
749+
* console.log(span.innerHTML);
750+
* // -> 'Log'
751+
*
752+
* // User clicks the <span> element:
753+
* // -> span MouseEvent('click', {bubbles: true})
754+
*
755+
* // ... wait 100ms for task to start running // !act
756+
* // -> 'Task ran'
757+
* ```
758+
* @category Task run hooks
759+
* @since v1.2.5
760+
*/
761+
/// useScheduleTaskRunCallback.2
656762

657763
/**
658764
* ProviderProps props are used with the Manager component, so that a TinyTick

src/@types/ui-react/index.d.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,17 @@ export function useScheduleTaskRun(
5757
configDeps?: DependencyList,
5858
): Id | undefined;
5959

60+
/// useScheduleTaskRun.2
61+
export function useScheduleTaskRun(
62+
args: {
63+
taskId: Id;
64+
arg?: string;
65+
startAfter?: TimestampMs | DurationMs;
66+
config?: TaskRunConfig;
67+
},
68+
configDeps?: DependencyList,
69+
): Id | undefined;
70+
6071
/// useScheduleTaskRunCallback
6172
export function useScheduleTaskRunCallback(
6273
taskId: Id,
@@ -66,6 +77,17 @@ export function useScheduleTaskRunCallback(
6677
configDeps?: DependencyList,
6778
): () => Id | undefined;
6879

80+
/// useScheduleTaskRunCallback.2
81+
export function useScheduleTaskRunCallback(
82+
args: {
83+
taskId: Id;
84+
arg?: string;
85+
startAfter?: TimestampMs | DurationMs;
86+
config?: TaskRunConfig;
87+
},
88+
configDeps?: DependencyList,
89+
): () => Id | undefined;
90+
6991
/// ProviderProps
7092
export type ProviderProps = {
7193
/// ProviderProps.manager

src/common/obj.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,14 @@ const objFrozen = object.isFrozen;
1010

1111
const objEntries = object.entries;
1212

13-
const isObject = (obj: unknown): boolean =>
13+
const objDel = <Value>(obj: IdObj<Value>, id: Id): IdObj<Value> => {
14+
delete obj[id];
15+
return obj;
16+
};
17+
18+
export type IdObj<Value> = {[id: string]: Value};
19+
20+
export const isObject = (obj: unknown): obj is IdObj<unknown> =>
1421
!isUndefined(obj) &&
1522
(ifNotUndefined(
1623
getPrototypeOf(obj),
@@ -21,13 +28,6 @@ const isObject = (obj: unknown): boolean =>
2128
() => true,
2229
) as boolean);
2330

24-
const objDel = <Value>(obj: IdObj<Value>, id: Id): IdObj<Value> => {
25-
delete obj[id];
26-
return obj;
27-
};
28-
29-
export type IdObj<Value> = {[id: string]: Value};
30-
3131
export const objFreeze = object.freeze;
3232

3333
export const objForEach = <Value>(

src/index.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import {
4141
mapToObj,
4242
} from './common/map.ts';
4343
import {
44+
isObject,
4445
objFilterUndefined,
4546
objForEach,
4647
objFreeze,
@@ -616,18 +617,33 @@ export const createManager: typeof createManagerDecl = (): Manager => {
616617
fluent((taskId) => mapSet(taskMap, taskId), taskId);
617618

618619
const scheduleTaskRun = (
619-
taskId: Id,
620+
taskIdOrArgs:
621+
| Id
622+
| {
623+
taskId: Id;
624+
arg?: string;
625+
startAfter?: TimestampMs | DurationMs;
626+
config?: TaskRunConfig;
627+
},
620628
arg?: string,
621629
startAfter: TimestampMs | DurationMs = 0,
622630
config: TaskRunConfig = {},
623631
): Id | undefined => {
624632
if (status == ManagerStatusValues.Stopping) {
625633
return undefined;
626634
}
635+
if (isObject(taskIdOrArgs)) {
636+
return scheduleTaskRun(
637+
taskIdOrArgs.taskId,
638+
taskIdOrArgs.arg,
639+
taskIdOrArgs.startAfter,
640+
taskIdOrArgs.config,
641+
);
642+
}
627643
const taskRunId = getUniqueId();
628644
const startTimestamp = normalizeTimestamp(startAfter);
629645
mapSet(taskRunMap, taskRunId, [
630-
id(taskId),
646+
id(taskIdOrArgs),
631647
arg,
632648
startTimestamp,
633649
validatedTestRunConfig(config),
@@ -637,7 +653,7 @@ export const createManager: typeof createManagerDecl = (): Manager => {
637653
]);
638654
insertTaskRunPointer(
639655
TaskRunState.Scheduled,
640-
id(taskId),
656+
id(taskIdOrArgs),
641657
taskRunId,
642658
startTimestamp,
643659
TaskRunReasonValues.Scheduled,

src/ui-react/hooks.ts

Lines changed: 61 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import type {
2929
useTaskRunRunning as useTaskRunRunningDecl,
3030
} from '../@types/ui-react/index.d.ts';
3131
import {arrayIsEqual} from '../common/array.ts';
32+
import {isObject} from '../common/obj.ts';
3233
import {isUndefined} from '../common/other.ts';
3334
import {Context} from './context.ts';
3435

@@ -79,6 +80,28 @@ const addAndDelListener = (thing: any, listenable: string, ...args: any[]) => {
7980
return () => thing?.delListener?.(listenerId);
8081
};
8182

83+
const useScheduleTaskRunImpl = (
84+
args: [taskId: Id, arg?: string, startAfter?: TimestampMs | DurationMs],
85+
config?: TaskRunConfig,
86+
configDeps: DependencyList = EMPTY_ARRAY,
87+
) => {
88+
const callback = useScheduleTaskRunCallbackImpl(args, config, configDeps);
89+
return useMemo(callback, [callback]);
90+
};
91+
92+
const useScheduleTaskRunCallbackImpl = (
93+
args: [taskId: Id, arg?: string, startAfter?: TimestampMs | DurationMs],
94+
config?: TaskRunConfig,
95+
configDeps: DependencyList = EMPTY_ARRAY,
96+
) => {
97+
const manager = useManager();
98+
return useCallback(
99+
() => manager?.scheduleTaskRun(...args, config),
100+
// eslint-disable-next-line react-hooks/exhaustive-deps
101+
[manager, ...args, ...configDeps],
102+
);
103+
};
104+
82105
export const useCreateManager: typeof useCreateManagerDecl = (
83106
create: () => Manager,
84107
createDeps: DependencyList = EMPTY_ARRAY,
@@ -134,34 +157,50 @@ export const useSetTask: typeof useSetTaskDecl = (
134157
};
135158

136159
export const useScheduleTaskRun: typeof useScheduleTaskRunDecl = (
137-
taskId: Id,
138-
arg?: string,
160+
taskIdOrArgs:
161+
| Id
162+
| {
163+
taskId?: Id;
164+
arg?: string;
165+
startAfter?: TimestampMs | DurationMs;
166+
config?: TaskRunConfig;
167+
},
168+
argOrConfigDeps?: string | DependencyList,
139169
startAfter?: TimestampMs | DurationMs,
140170
config?: TaskRunConfig,
141-
configDeps: DependencyList = EMPTY_ARRAY,
142-
) => {
143-
const callback = useScheduleTaskRunCallback(
144-
taskId,
145-
arg,
146-
startAfter,
147-
config,
148-
configDeps,
171+
configDeps?: DependencyList,
172+
) =>
173+
(useScheduleTaskRunImpl as any)(
174+
...(isObject(taskIdOrArgs)
175+
? [
176+
[taskIdOrArgs.taskId, taskIdOrArgs.arg, taskIdOrArgs.startAfter],
177+
taskIdOrArgs.config,
178+
argOrConfigDeps,
179+
]
180+
: [[taskIdOrArgs, argOrConfigDeps, startAfter], config, configDeps]),
149181
);
150-
return useMemo(callback, [callback]);
151-
};
152182

153183
export const useScheduleTaskRunCallback: typeof useScheduleTaskRunCallbackDecl =
154184
(
155-
taskId: Id,
156-
arg?: string,
185+
taskIdOrArgs:
186+
| Id
187+
| {
188+
taskId?: Id;
189+
arg?: string;
190+
startAfter?: TimestampMs | DurationMs;
191+
config?: TaskRunConfig;
192+
},
193+
argOrConfigDeps?: string | DependencyList,
157194
startAfter?: TimestampMs | DurationMs,
158195
config?: TaskRunConfig,
159-
configDeps: DependencyList = EMPTY_ARRAY,
160-
) => {
161-
const manager = useManager();
162-
return useCallback(
163-
() => manager?.scheduleTaskRun(taskId, arg, startAfter, config),
164-
// eslint-disable-next-line react-hooks/exhaustive-deps
165-
[manager, taskId, arg, startAfter, ...configDeps],
196+
configDeps?: DependencyList,
197+
) =>
198+
(useScheduleTaskRunCallbackImpl as any)(
199+
...(isObject(taskIdOrArgs)
200+
? [
201+
[taskIdOrArgs.taskId, taskIdOrArgs.arg, taskIdOrArgs.startAfter],
202+
taskIdOrArgs.config,
203+
argOrConfigDeps,
204+
]
205+
: [[taskIdOrArgs, argOrConfigDeps, startAfter], config, configDeps]),
166206
);
167-
};

0 commit comments

Comments
 (0)