Util APIs
APIs for various utilities available around the whole API surface.
#Progress
interface Progress {
(progress?: ProgressData | null): void;
(completed?: number | null, total?: number | null, indeterminate?: boolean): void;
data: ProgressData;
completed: number | undefined;
indeterminate: boolean | undefined;
total: number | undefined;
destroy: () => void;
toJSON: () => ProgressData;
}
type ProgressData = {completed?: number; total?: number; indeterminate?: boolean};
Utility for reporting progress. It supports multiple methods to set current progress.
The total value is always optional, omitting it creates an indeterminate progress bar.
indeterminate
parameter forces progress bar into indeterminate mode (animated stripes).
The way how progress value is displayed to the user can be customized with progressFormatter
processor config.
#progress(data)
Pass a progress data object with completed
, total
, and indeterminate
values. All values are optional. Pass anything false, or an empty object to reset the progress to undefined.
This method updates both values, omitting one resets it to undefined.
progress({completed: 0.2, total: 1});
progress({completed: 1024});
progress(null); // reset
#progress(completed, total?, indeterminate?)
Pass completed
and total
as function parameters. Both values are optional.
This method updates both values, omitting one resets it to undefined.
progress(3, 10); // normal progress
progress(3, 10, true); // forced indeterminate progress (animated stripes)
progress(3); // implicit indeterminate progress
progress(null); // reset both to null
#completed
/ total
Set or read one of the progress values individually:
progress.completed = completed;
progress.total = total;
#data
Read, or set progress data object by assigning it to progress.data
:
progress.data = {completed, total};
progress.data = {completed};
progress.data = {};
progress.data = null;
This is the same as calling progress(data)
, with the difference that you can also read the current value.
#OutputEmitters
interface OutputEmitters {
file: (path: string, meta?: OutputMeta) => void;
directory: (path: string, meta?: OutputMeta) => void;
url: (url: string, meta?: OutputMeta) => void;
string: (contents: string, meta?: {type?: string} & OutputMeta) => void;
error: (error: Error | string, meta?: OutputMeta) => void;
}
interface OutputMeta {
flair?: Flair;
badge?: Badge;
}
export interface Flair {
variant?: Variant;
title: string;
description?: string;
}
export interface Badge {
variant?: Variant;
title: string;
icon: string;
}
Utilities for emitting output items. These show up in profile and global Outputs drawers, where they can be comfortably consumed, opened, navigated to, or copied.
Every output emitter accepts an optional OutputMeta
config. Currently it is used for adding flairs and or badges to output items. These are displayed next to the output payload in the UI. For example, encode & optimize plugins use flair to display the percentage of file size savings.
The badge icon
property can be a name of one of the icons built into the app, or a full path to an svg file. In case you are using your own svg file, ensure it's using currentColor
to color all if its elements, otherwise it's going to look bad, and down right unreadable in one of the themes.
Currently, these icon names are available: article
, bell
, binary
, book
, bug
, calendar
, changelog
, check
, check-all
, circle
, circle-check
, circle-plus
, circle-x
, clear-all
, clock
, cog
, copy
, dependency
, drop
, edit
, error
, export
, file
, file-add
, file-missing
, file-open
, files
, folder
, folder-add
, folder-missing
, folder-open
, github
, globe
, hdd
, help
, history
, home
, import
, info
, input
, install
, link
, logo
, logs
, loupe
, npm
, open-external
, operation
, output
, payload
, plugins
, plus
, power
, processor
, puzzle
, refresh
, search
, selector
, star
, tag
, text
, time
, trash
, undo
, update
, update-check
, visibility
, visibility-off
, warning
, x
.
#file
Type: (path: string, meta?: OutputMeta) => void
Emits a file. Path has to be a path to a file created or modified by processor.
#directory
Type: (path: string, meta?: OutputMeta) => void
Emits a directory. Path has to be a path to a directory created or modified by processor.
#url
Type: (url: string, meta?: OutputMeta) => void
Emits a URL.
#string
Type: (contents: string, meta?: {type?: string} & OutputMeta) => void
Emits a string. This is intended for stuff like tokens, keys, or any other string values.
The OutputMeta
for string accepts an additional type
property which defines a string mime type, which is text/plain
by default. You can change it to whatever you like. This currently serves no purpose, but in future when processor outputs can be piped into other processors, string types might be used for filtering.
If you want to just inform the user about something related to the operation progress, more appropriate would be to use console.*
methods that show in operation logs.
Outputs are items that could potentially be consumed by other processors. Messages such as "All done!" do not belong here.
#warning
Type: (message: string, meta?: OutputMeta) => void
Emits a warning.
#error
Type: (error: Error | string, meta?: OutputMeta) => void
Emits an error. Tha value can be an error object, or a string with a message.
Note: Calling console.error('str')
both logs the error in operation log and emits it as an error output item. It's essentially the same as doing:
console.log('str');
output.error('str');
#PreparatorUtils
interface PreparatorUtils {
action: 'drop' | 'paste';
modifiers: string;
title(value: string | undefined | null): void;
dependencies: {[key: string]: unknown};
settings: AppSettings;
dataPath: string;
nodePath: string;
// CommonModals
alert(data: ModalData): Promise<void>;
confirm(data: ModalData): Promise<ModalResult<boolean>>;
prompt(data: ModalData, stringOptions?: OptionString): Promise<ModalResult<string>>;
promptOptions<T extends OptionsData | undefined = undefined>(
data: ModalData,
schema: OptionsSchema<T>
): Promise<ModalResult<T>>;
showOpenDialog(options: OpenDialogOptions): Promise<OpenDialogReturnValue>;
showSaveDialog(options: SaveDialogOptions): Promise<SaveDialogReturnValue>;
openModalWindow<T = unknown>(options: string | OpenWindowOptions, payload: unknown): Promise<T>;
}
Utilities available in operation preparator. CommonModals are documented below.
#action
Type: 'drop' | 'paste'
Name of the action that added items into the payload. This might grow in the future.
Note: paste
action always comes with an empty modifiers id
#modifiers
Type: string
A string uniquely identifying keyboard modifiers held during drop event that added items to the operation.
For example, if user holds Ctrl and Shift while dropping items into the profile, this will be Ctrl+Shift
.
Available modifiers: Alt
, Ctrl
, Meta
, Shift
Notes:
- Modifiers in the string are always PascalCased and in alphabetical order.
Meta
is Win key on Windows and Command on Mac.'Shift'
ID is reserved for tweak options on drop, but other modifier keys and all modifier combinations are up for grabs.- On macOS
Meta
andCtrl
are reserved for drag & drop features built into the OS.
#title
Type: (value: string | undefined | null) => void
Sets or deletes operation title. By default, operation titles are constructed from its payload (file paths, domains, etc), but if you have something more descriptive or relevant, you can use this to overwrite it.
#dependencies
Type: {[key: string]: unknown}
Payloads of dependencies the processor depends on.
#settings
interface AppSettings {
fontSize: number;
compact: boolean;
theme: 'os' | 'light' | 'dark';
developerMode: boolean;
editCommand: string;
}
User configured application settings t hat might be useful for modal windows or something else.
#dataPath
A path where plugin can save it's session data that should persist. Intended for config files, credentials, logs, history, and such.
#nodePath
Type: string
Path to the app managed Node.js binary in case you need to spawn it or pass to the modal window.
#modals
PreparatorUtils have also access to CommonModals, which are documented below. Example:
await utils.alert({title: 'Foo', message: `Foo happened because of bar.`});
#Download
function download(url: string | URL, destination: string, options?: DownloadOptions): Promise<string>;
interface DownloadOptions {
onProgress?: (progress: {completed: number; total?: number}) => void;
filename?: string;
timeout?: number;
signal?: AbortSignal;
}
A simple utility to download a file from the internet. Follows redirects, extracts the source filename, and resolves with the final downloaded filename (not path, just filename).
#url
Type: string | URL
required
Source url to the file to be downloaded. Can be a string with URL, or a new URL()
object.
#destination
Type: string
required
Path to the destination directory.
#options
Type: DownloadOptions
optional
Object with download options.
onProgress
Type: (progress: {completed: number, total?: number}) => void
An onProgress handler. Designed so you can just plug in Progress
into it:
utils.download(url, destination, {opProgress: utils.progress});
filename
Type: string
By default, download()
retrieves filename from response headers or a passed url, but you can make it to ignore those, and use this filename instead.
timeout
Type: number
Socket timeout in milliseconds.
signal
Type: AbortSignal
See AbortSignal
on MDN.
#Return
Returns filename extracted from source headers, or a URL when not in headers.
It'll return the extracted filename even when destination filename is forced by options.filename
.
#Extract
function extract(archivePath: string, options?: ExtractOptions): Promise<string[] | ExtractListDetailItem[]>;
function extract(
archivePath: string,
destinationPath: string,
options?: ExtractOptions
): Promise<string[] | ExtractListDetailItem[]>;
interface ExtractOptions {
overwrite?: boolean;
listDetails?: boolean;
onProgress?: (progress: ProgressData) => void;
onLog?: (message: string) => void;
}
interface ExtractListDetailItem {
name: string; // File name
path: string; // Full path to the file
size: number;
isDirectory: boolean;
isFile: boolean;
}
A utility to extract files from an archive. Automatically decompresses .tar.gz, .tar.xz, ...
.
Returns a list of root files and folders extracted from the archive.
Quick example
const files = await extract('archive.zip'); // extracts into same directory as archive
const files = await extract('archive.zip', 'out'); // specify destination directory
console.log(file); // list of root files from extracted archive
#archivePath
Type: string
required
Path to the archive to extract.
#destinationPath
Type: string
optional
Path to the destination directory. By default, the directory of the archive will be used.
#options
Type: ExtractOptions
optional
Extract options object.
overwrite
Type: boolean
optional
Default: false
Passing true
will make extraction overwrite any existing files.
listDetails
Type: boolean
optional
Default: false
Wether the returned list should contain file details (path, size, isDirectory, isFile). By default, only filename strings are returned.
onProgress
Type: (progress: ProgressData) => void
optional
Progress reporter designed to accepts Progress
util. Example:
const files = await extract('archive.zip', {onProgress: util.progress});
onLog
Type: (message: string) => void
optional
Reports extraction logs.
Example
Disabled:
console.log(await extract('archive.zip', {listDetails: false}));
[ "file.ext" ]
Enabled:
console.log(await extract('archive.zip', {listDetails: true}));
[
{
path: "file.ext",
size: 1024,
isDirectory: false,
isFile: true,
}
]
#Return
Returns either list of root or all filenames or file details in the extracted file.
#CommonModals
interface CommonModals {
alert(data: ModalData): Promise<void>;
confirm(data: ModalData): Promise<ModalResult<boolean>>;
prompt(data: ModalData, stringOptions?: OptionString): Promise<ModalResult<string>>;
promptOptions<T extends OptionsData | undefined = undefined>(
data: ModalData,
schema: OptionsSchema<T>
): Promise<ModalResult<T>>;
showOpenDialog(options: OpenDialogOptions): Promise<OpenDialogReturnValue>;
showSaveDialog(options: SaveDialogOptions): Promise<SaveDialogReturnValue>;
openModalWindow<T = unknown>(options: string | OpenWindowOptions, payload?: unknown): Promise<ModalResult<T>>;
}
interface ModalData {
variant?: 'success' | 'info' | 'warning' | 'danger';
title?: string;
message?: string;
details?: string;
}
interface ModalResult<T = unknown> {
canceled: boolean;
payload: T;
modifiers: string;
}
interface OpenWindowOptions {
path: string;
title?: string;
width?: number; // Suggested width
height?: number; // Suggested height
minWidth?: number;
minHeight?: number;
}
Modal interfaces available in various places around the API.
#alert
Type: (data: ModalData) => Promise<void>
Displays an alert modal window to the user with an OK button to close it. Returns a promise that resolves once the modal has been closed.
data
interface ModalData {
variant?: 'success' | 'info' | 'warning' | 'danger';
title?: string;
message?: string;
details?: string;
}
Example
await alert({
variant: 'danger',
title: 'Error',
message: 'Some error message.',
});
#confirm
Type: (data: ModalData) => Promise<ModalResult<boolean>>
Displays a confirmation dialogue with OK and Cancel buttons. Returns a promise that resolves with ModalResult<boolean>
interface, where payload is either true
when user confirmed, or false
when they closed the modal.
data
interface ModalData {
variant?: 'success' | 'info' | 'warning' | 'danger';
title?: string;
message?: string;
details?: string;
}
Return
Returns ModalResult<boolean>
, which looks like this:
{
canceled: boolean;
payload: boolean;
modifiers: string; // example: 'alt+ctrl+shift'
}
Example
const result = await confirm({
title: 'Question',
message: 'Do you agree?',
});
if (result.payload) {
// user agreed
}
#prompt
Type: (data: ModalData, stringOptions?: OptionString) => Promise<ModalResult<string>>
Prompts user for a string input. Resolves with ModalResult<string>
interface.
data
interface ModalData {
variant?: 'success' | 'info' | 'warning' | 'danger';
title?: string;
message?: string;
details?: string;
}
stringOptions
Validating & formatting options of string option schema, that is:
{
default?: string;
rows?: number;
cols?: number; // set above 1 to create a textarea
min?: number;
max?: number;
validator?: (value: string) => boolean;
asyncValidator?: (value: string) => Promise<boolean>;
}
Return
Returns ModalResult<string>
, which looks like this:
{
canceled: boolean;
payload: string;
modifiers: string; // example: 'alt+ctrl+shift'
}
Example
const result = await prompt({
title: 'Credentials',
message: 'Enter key:',
});
if (!result.canceled) {
console.log(result.payload); // users key
}
#promptOptions
Type: <T = unknown>(data: ModalData, optionsSchema: OptionsSchema[]) => Promise<ModalResult<T>>
Prompts user with options constructed from passed options schema, similar to defining processor options. Resolves with ModalResult<T>
interface
data
interface ModalData {
variant?: 'success' | 'info' | 'warning' | 'danger';
title?: string;
message?: string;
details?: string;
}
optionsSchema
OptionsSchema to construct options UI for user to fill. Same as defining processor options.
Return
Returns ModalResult<T>
, where T
is data the optionsSchema
should produce. Looks like this:
{
canceled: boolean;
payload: T;
modifiers: string; // example: 'alt+ctrl+shift'
}
Example
const result = await promptOptions({title: 'Form', message: 'Fill this:'}, [
{name: 'foo', type: 'boolean', default: false},
]);
if (!result.canceled) {
console.log(result.payload.foo); // boolean
}
#showOpenDialog
Type: (options: OpenDialogOptions) => Promise<OpenDialogReturnValue>
Creates a dialog to retrieve file or directory path(s) to open.
This is just a proxy to Electron's dialog.showOpenDialog
without the browserWindow
parameter.
Example
const result = await utils.showOpenDialog({properties: ['openFile']});
if (!result.canceled) {
console.log(result.filePaths[0]);
}
#showSaveDialog
Type: (options: SaveDialogOptions) => Promise<SaveDialogReturnValue>
Creates a dialog to retrieve a destination file path.
This is just a proxy to Electron's dialog.showSaveDialog
without the browserWindow
parameter.
Example
const result = await utils.showSaveDialog({properties: ['createDirectory']});
if (!result.canceled) {
console.log(result.filePath);
}
#openModalWindow
Type: <T = unknown>(options: string | OpenWindowOptions, payload?: any): Promise<T>
Allows preparator to open a window with its own UI to do something to the payload.
The first argument is either path to the html
that renders the UI (nodeIntegration enabled), or an object with options.
path
to the html is relative from the root of the plugin.
interface OpenWindowOptions {
path: string;
width?: number; // Suggested width
height?: number; // Suggested height
minWidth?: number;
minHeight?: number;
}
Inside the window, you can use the @drovp/utils for modal-window
to communicate with the preparator and resolve with the new or modified payload.
Example
Main plugin file:
plugin.registerProcessor({
// ... other options
operationPreparator: async (payload, utils) => {
const {canceled, payload} = await utils.openModalWindow('window.html', payload);
return canceled ? null : payload;
},
});
Window HTML file:
<DOCTYPE! html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Plugin window</title>
</head>
<body>
<div id="app"></div>
<script src="/window.js"></script>
</body></html
></DOCTYPE!>
Window JS file:
const {getPayload, resolve, openContextMenu} = require('@drovp/utils/modal-window');
getPayload().then((payload) => {
console.log(payload); // Payload passed via openModalWindow(..., payload);
const newPayload = await renderSomeUIAndDoSomething(payload);
resolve(newPayload); // This also closes the window
// If you want to close the window without resolving, just do:
window.close();
});