import { StateRepository } from '../core'; /** * Service for creating and monitoring long-running background tasks * * The TaskRepository provides a way to create background tasks that execute * asynchronously on the server. This is useful for operations that take significant * time to complete, such as bulk data processing, report generation, or data imports. * * Tasks are tracked by unique IDs and emit events ({@link TaskEventType}) as they * progress through their lifecycle. A task created through {@link create} is * followed for you, and an event is dispatched once it finishes. Listening to * those events is the way to give users feedback on progress and completion. * Use {@link getStatus} for tasks that were not created in this session, or for * a one-off check. * * Since TaskRepository extends {@link StateRepository}, components can call * {@link StateRepository.subscribe} to react to task state changes. * * @example Listening to task events * ```ts * import { * PlatformServiceName, * TaskEvent, * TaskEventType, * } from '@limetech/lime-web-components'; * * const eventDispatcher = platform.get(PlatformServiceName.EventDispatcher); * * const onTaskSuccess = (event: TaskEvent) => { * // Suppress the built-in snackbar and show our own message instead * event.preventDefault(); * * const { task } = event.detail; * console.log('Task finished', task.id, task.result); * }; * * const onTaskFailure = (event: TaskEvent) => { * const { error } = event.detail; * console.error('Task failed', error); * }; * * eventDispatcher.addListener(TaskEventType.Success, onTaskSuccess); * eventDispatcher.addListener(TaskEventType.Failed, onTaskFailure); * * // Remember to remove the listeners in `disconnectedCallback()` * eventDispatcher.removeListener(TaskEventType.Success, onTaskSuccess); * eventDispatcher.removeListener(TaskEventType.Failed, onTaskFailure); * ``` * * @public * @group Tasks * @see {@link TaskEventType} for the events a task emits * @see {@link TaskStatus} for the shape of a task status */ export interface TaskRepository extends StateRepository { /** * Create a new background task on the server * * This method initiates a long-running operation on the server and returns * a task ID that can be used to monitor the task's progress. The task will * execute asynchronously, and task events will be emitted as it progresses. * * @param url - URL of the server endpoint that will create and execute the task. * A URL without a leading slash is resolved against the current * database * @param data - Task-specific data to send to the server endpoint * @param cancelAction - Whether the notification shows a cancel button that lets * the user stop the task before it starts. Defaults to `true` * @param message - Custom notification message to display to the user. If not * provided, a default message will be shown * @returns A promise that resolves to the task ID once the task has been created. * Resolves to `void` if the user cancels, or if the task could not be * created * * @example Creating a simple background task * ```ts * import { PlatformServiceName } from '@limetech/lime-web-components'; * * const taskRepository = platform.get(PlatformServiceName.TaskRepository); * * const taskId = await taskRepository.create('api/v1/generate-report', { * reportType: 'sales', * year: 2024, * }); * * console.log('Report task created', taskId); * ``` * * @example Creating a task with a custom message * ```ts * import { PlatformServiceName } from '@limetech/lime-web-components'; * * const taskRepository = platform.get(PlatformServiceName.TaskRepository); * * // `cancelAction` is `true` by default, so pass `false` to hide the cancel button * const taskId = await taskRepository.create( * 'api/v1/import-data', * { sourceFile: 'data.csv' }, * false, * 'Importing data from CSV file...' * ); * * // No id also means the task failed to start, not only that it was cancelled * if (!taskId) { * console.log('The import did not start'); * } * ``` * * @see {@link TaskEventType.Created} which is dispatched once the task exists * @see {@link getStatus} to follow the task after it has been created */ create(url: string, data: unknown, cancelAction?: boolean, message?: string): Promise; /** * Get the current status of one or more tasks * * This method queries the server for the current state of the specified tasks. * Use this to check task progress, retrieve results, or verify completion. * * @param ids - Array of task IDs to query * @returns A promise that resolves to an array of {@link TaskStatus} objects. A * task whose status cannot be read is left out, so the array can be * shorter than `ids`, or empty * * @example Checking status of a single task * ```ts * import { PlatformServiceName, TaskState } from '@limetech/lime-web-components'; * * const taskRepository = platform.get(PlatformServiceName.TaskRepository); * * // The array is empty when the status could not be read * const [status] = await taskRepository.getStatus(['task-123']); * * if (status?.status === TaskState.Success) { * console.log('Task result', status.result); * } else if (status?.status === TaskState.Failure) { * console.error('Task failed'); * } else { * console.log('Task still running...'); * } * ``` * * @example Monitoring multiple tasks * ```ts * import { PlatformServiceName, TaskState } from '@limetech/lime-web-components'; * * const taskRepository = platform.get(PlatformServiceName.TaskRepository); * * const taskIds = ['task-1', 'task-2', 'task-3']; * * // Tasks whose status could not be read are missing from the array * const statuses = await taskRepository.getStatus(taskIds); * * const activeStates = new Set([ * TaskState.Pending, * TaskState.Started, * TaskState.Retry, * ]); * * const completed = statuses.filter((s) => s.status === TaskState.Success); * const failed = statuses.filter((s) => s.status === TaskState.Failure); * const inProgress = statuses.filter((s) => activeStates.has(s.status)); * * console.log( * `${completed.length} completed, ${failed.length} failed, ${inProgress.length} in progress` * ); * ``` * * @see {@link TaskState} for the states a task can be in */ getStatus(ids: string[]): Promise; } /** * @public * @group Tasks */ export declare enum TaskState { /** * Task state is unknown */ Pending = "PENDING", /** * Task was started by a worker */ Started = "STARTED", /** * Task is waiting for retry */ Retry = "RETRY", /** * Task succeeded */ Success = "SUCCESS", /** * Task failed */ Failure = "FAILURE" } /** * @public * @group Tasks */ export interface TaskStatus { /** * ID of the task */ id: string; /** * The state of the task */ status: TaskState; /** * The result of the task once it has finished its execution */ result?: string; } /** * Events dispatched by the task service * * Listen to these through the {@link EventDispatcher} service. They are not * dispatched on `window`. * * {@link TaskEventType.Success} and {@link TaskEventType.Failed} are cancelable. * Call `preventDefault()` on the event to stop the default notification, for * example to show your own message instead. * * @example Listening to task events * ```ts * import { * PlatformServiceName, * TaskEvent, * TaskEventType, * } from '@limetech/lime-web-components'; * * const eventDispatcher = platform.get(PlatformServiceName.EventDispatcher); * * const onTaskSuccess = (event: TaskEvent) => { * // Suppress the built-in snackbar and show our own message instead * event.preventDefault(); * * const { task } = event.detail; * console.log('Task finished', task.id, task.result); * }; * * const onTaskFailure = (event: TaskEvent) => { * const { error } = event.detail; * console.error('Task failed', error); * }; * * eventDispatcher.addListener(TaskEventType.Success, onTaskSuccess); * eventDispatcher.addListener(TaskEventType.Failed, onTaskFailure); * * // Remember to remove the listeners in `disconnectedCallback()` * eventDispatcher.removeListener(TaskEventType.Success, onTaskSuccess); * eventDispatcher.removeListener(TaskEventType.Failed, onTaskFailure); * ``` * * @public * @group Tasks */ export declare enum TaskEventType { /** * Dispatched when a task has been created. * * @see {@link TaskEvent} */ Created = "task.created", /** * Dispatched when the task has successfully been completed * * @see {@link TaskEvent} */ Success = "task.success", /** * Dispatched if an error occured while running the task * * @see {@link TaskEvent} */ Failed = "task.failed" } /** * @public * @group Tasks */ export type TaskEventDetail = { task: TaskStatus; error?: unknown; }; /** * @public * @group Tasks */ export type TaskEvent = CustomEvent;