Skip to content

Commit

Permalink
Add types to the ad-hoc plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
jcbrand committed Apr 3, 2024
1 parent fb60206 commit 7aca70f
Show file tree
Hide file tree
Showing 12 changed files with 220 additions and 101 deletions.
40 changes: 15 additions & 25 deletions src/headless/plugins/adhoc/api.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
/**
* @typedef {import('./utils').AdHocCommand} AdHocCommand
* @typedef {import('./utils').AdHocCommandFields} AdHocCommandFields
*/
import log from '../../log.js';
import _converse from '../../shared/_converse.js';
import api from '../../shared/api/index.js';
Expand All @@ -19,7 +23,7 @@ export default {
adhoc: {
/**
* @method api.adhoc.getCommands
* @param { String } to_jid
* @param {string} to_jid
*/
async getCommands (to_jid) {
try {
Expand All @@ -37,34 +41,20 @@ export default {

/**
* @method api.adhoc.fetchCommandForm
* @param {string} jid
* @param {string} node
* @returns {Promise<AdHocCommandFields>}
*/
async fetchCommandForm (command) {
const node = command.node;
const jid = command.jid;
async fetchCommandForm (jid, node) {
const stanza = $iq({
'type': 'set',
'to': jid
type: 'set',
to: jid
}).c('command', {
'xmlns': Strophe.NS.ADHOC,
'node': node,
'action': 'execute'
xmlns: Strophe.NS.ADHOC,
action: 'execute',
node,
});
try {
return getCommandFields(await api.sendIQ(stanza), jid);

} catch (e) {
if (e === null) {
log.error(`Error: timeout while trying to execute command for ${jid}`);
} else {
log.error(`Error while trying to execute command for ${jid}`);
log.error(e);
}
const { __ } = _converse;
return {
instructions: __('An error occurred while trying to fetch the command form'),
fields: []
}
}
return getCommandFields(await api.sendIQ(stanza), jid);
},

/**
Expand Down
21 changes: 21 additions & 0 deletions src/headless/plugins/adhoc/utils.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,40 @@
/**
* @typedef {import('lit').TemplateResult} TemplateResult
*/
import sizzle from 'sizzle';
import converse from '../../shared/api/public.js';

const { Strophe, u } = converse.env;

/**
* @typedef {Object} AdHocCommand
* @property {string} action
* @property {string} node
* @property {string} sessionid
* @property {string} status
*/

/**
* @param {Element} stanza
* @returns {AdHocCommand[]}
*/
export function parseForCommands (stanza) {
const items = sizzle(`query[xmlns="${Strophe.NS.DISCO_ITEMS}"][node="${Strophe.NS.ADHOC}"] item`, stanza);
return items.map(u.getAttributes);
}

/**
* @typedef {Object} AdHocCommandFields
* @property {string} sessionid
* @property {string} [instructions]
* @property {TemplateResult[]} [fields]
* @property {string[]} [actions]
*/

/**
* @param {Element} iq
* @param {string} [jid]
* @returns {AdHocCommandFields}
*/
export function getCommandFields (iq, jid) {
const cmd_el = sizzle(`command[xmlns="${Strophe.NS.ADHOC}"]`, iq).pop();
Expand Down
27 changes: 12 additions & 15 deletions src/headless/types/plugins/adhoc/api.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,16 @@ declare namespace _default {
namespace adhoc {
/**
* @method api.adhoc.getCommands
* @param { String } to_jid
* @param {string} to_jid
*/
function getCommands(to_jid: string): Promise<any>;
function getCommands(to_jid: string): Promise<import("./utils.js").AdHocCommand[]>;
/**
* @method api.adhoc.fetchCommandForm
* @param {string} jid
* @param {string} node
* @returns {Promise<AdHocCommandFields>}
*/
function fetchCommandForm(command: any): Promise<{
sessionid: any;
instructions: any;
fields: any;
actions: any[];
} | {
instructions: any;
fields: any[];
}>;
function fetchCommandForm(jid: string, node: string): Promise<import("./utils.js").AdHocCommandFields>;
/**
* @method api.adhoc.runCommand
* @param { String } jid
Expand All @@ -29,13 +24,15 @@ declare namespace _default {
[k: string]: string;
}[]): Promise<{
note: any;
sessionid?: any;
instructions?: any;
fields?: any;
actions?: any[];
sessionid?: string;
instructions?: string;
fields?: import("./utils.js").TemplateResult[];
actions?: string[];
status: any;
}>;
}
}
export default _default;
export type AdHocCommand = import('./utils').AdHocCommand;
export type AdHocCommandFields = import('./utils').AdHocCommandFields;
//# sourceMappingURL=api.d.ts.map
36 changes: 30 additions & 6 deletions src/headless/types/plugins/adhoc/utils.d.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,39 @@
/**
* @typedef {Object} AdHocCommand
* @property {string} action
* @property {string} node
* @property {string} sessionid
* @property {string} status
*/
/**
* @param {Element} stanza
* @returns {AdHocCommand[]}
*/
export function parseForCommands(stanza: Element): AdHocCommand[];
/**
* @typedef {Object} AdHocCommandFields
* @property {string} sessionid
* @property {string} [instructions]
* @property {TemplateResult[]} [fields]
* @property {string[]} [actions]
*/
export function parseForCommands(stanza: Element): any;
/**
* @param {Element} iq
* @param {string} [jid]
* @returns {AdHocCommandFields}
*/
export function getCommandFields(iq: Element, jid?: string): {
sessionid: any;
instructions: any;
fields: any;
actions: any[];
export function getCommandFields(iq: Element, jid?: string): AdHocCommandFields;
export type AdHocCommand = {
action: string;
node: string;
sessionid: string;
status: string;
};
export type AdHocCommandFields = {
sessionid: string;
instructions?: string;
fields?: TemplateResult[];
actions?: string[];
};
export type TemplateResult = import('lit').TemplateResult;
//# sourceMappingURL=utils.d.ts.map
43 changes: 35 additions & 8 deletions src/plugins/adhoc-views/adhoc-commands.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
/**
* @typedef {import('@converse/headless/types/plugins/adhoc/utils').AdHocCommand} AdHocCommand
* @typedef {import('@converse/headless/types/plugins/adhoc/utils').AdHocCommandFields} AdHocCommandFields
*/
import 'shared/autocomplete/index.js';
import tplAdhoc from './templates/ad-hoc.js';
import { CustomElement } from 'shared/components/element.js';
Expand All @@ -7,6 +11,17 @@ import { getNameAndValue } from 'utils/html.js';

const { Strophe, sizzle } = converse.env;

/**
* @typedef {Object} UIProps
* @property {string} instructions
* @property {string} jid
* @property {string} [alert]
* @property {'danger'|'primary'} [alert_type]
* @property {'cancel'|'complete'|'execute'|'next'|'prev'} name
*
* @typedef {AdHocCommand & AdHocCommandFields & UIProps} AdHocCommandUIProps
*/


export default class AdHocCommands extends CustomElement {
static get properties () {
Expand All @@ -25,7 +40,7 @@ export default class AdHocCommands extends CustomElement {
this.view = 'choose-service';
this.fetching = false;
this.showform = '';
this.commands = [];
this.commands = /** @type {AdHocCommandUIProps[]} */([]);
}

render () {
Expand Down Expand Up @@ -61,13 +76,13 @@ export default class AdHocCommands extends CustomElement {

if (supported) {
try {
this.commands = await api.adhoc.getCommands(jid);
this.commands = /** @type {AdHocCommandUIProps[]} */(await api.adhoc.getCommands(jid));
this.view = 'list-commands';
} catch (e) {
log.error(e);
this.alert_type = 'danger';
this.alert = __('Sorry, an error occurred while looking for commands on that entity.');
this.commands = [];
this.commands = /** @type {AdHocCommandUIProps[]} */([]);
log.error(e);
return;
}
Expand All @@ -81,15 +96,27 @@ export default class AdHocCommands extends CustomElement {
ev.preventDefault();
const node = ev.target.getAttribute('data-command-node');
const cmd = this.commands.filter(c => c.node === node)[0];
const { jid } = cmd;

if (this.showform === node) {
this.showform = '';
this.requestUpdate();
} else {
const form = await api.adhoc.fetchCommandForm(cmd);
cmd.sessionid = form.sessionid;
cmd.instructions = form.instructions;
cmd.fields = form.fields;
cmd.actions = form.actions;
try {
const form = await api.adhoc.fetchCommandForm(jid, node);
cmd.sessionid = form.sessionid;
cmd.instructions = form.instructions;
cmd.fields = form.fields;
cmd.actions = form.actions;
} catch (e) {
if (e === null) {
log.error(`Error: timeout while trying to execute command for ${jid}`);
} else {
log.error(`Error while trying to execute command for ${jid}`);
log.error(e);
}
cmd.instructions = __('An error occurred while trying to fetch the command form');
}
this.showform = node;
}
}
Expand Down
67 changes: 41 additions & 26 deletions src/plugins/adhoc-views/templates/ad-hoc-command-form.js
Original file line number Diff line number Diff line change
@@ -1,43 +1,58 @@
/**
* @typedef {import('../adhoc-commands').default} AdHocCommands
* @typedef {import('../adhoc-commands').AdHocCommandUIProps} AdHocCommandUIProps
*/
import { html } from 'lit';
import { __ } from 'i18n';
import { html } from "lit";


const action_map = {
execute: __('Execute'),
prev: __('Previous'),
next: __('Next'),
complete: __('Complete'),
}
};

/**
* @param {AdHocCommands} el
* @param {AdHocCommandUIProps} command
*/
export default (el, command) => {
const i18n_cancel = __('Cancel');

return html`
<span> <!-- Don't remove this <span>,
this is a workaround for a lit bug where a <form> cannot be removed
if it contains an <input> with name "remove" -->
<span>
<!-- Don't remove this <span>,
this is a workaround for a lit bug where a <form> cannot be removed
if it contains an <input> with name "remove" -->
<form>
${ command.alert ? html`<div class="alert alert-${command.alert_type}" role="alert">${command.alert}</div>` : '' }
<fieldset class="form-group">
<input type="hidden" name="command_node" value="${command.node}"/>
<input type="hidden" name="command_jid" value="${command.jid}"/>
${command.alert
? html`<div class="alert alert-${command.alert_type}" role="alert">${command.alert}</div>`
: ''}
<fieldset class="form-group">
<input type="hidden" name="command_node" value="${command.node}" />
<input type="hidden" name="command_jid" value="${command.jid}" />
<p class="form-instructions">${command.instructions}</p>
${ command.fields }
</fieldset>
<fieldset>
${ command.actions.map((action) =>
html`<input data-action="${action}"
@click=${(ev) => el.executeAction(ev)}
<p class="form-instructions">${command.instructions}</p>
${command.fields ?? []}
</fieldset>
<fieldset>
${command.actions?.map(
(action) =>
html`<input
data-action="${action}"
@click=${(ev) => el.executeAction(ev)}
type="button"
class="btn btn-primary"
value="${action_map[action]}"
/>`
)}<input
type="button"
class="btn btn-primary"
value="${action_map[action]}">`)
}<input type="button"
class="btn btn-secondary button-cancel"
value="${i18n_cancel}"
@click=${(ev) => el.cancel(ev)}>
</fieldset>
</form>
class="btn btn-secondary button-cancel"
value="${i18n_cancel}"
@click=${(ev) => el.cancel(ev)}
/>
</fieldset>
</form>
</span>
`;
}
};
9 changes: 9 additions & 0 deletions src/plugins/adhoc-views/templates/ad-hoc-command.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
/**
* @typedef {import('@converse/headless/types/plugins/adhoc/utils').AdHocCommand} AdHocCommand
* @typedef {import('../adhoc-commands').default} AdHocCommands
* @typedef {import('../adhoc-commands').AdHocCommandUIProps} AdHocCommandUIProps
*/
import { html } from "lit";
import tplCommandForm from './ad-hoc-command-form.js';

/**
* @param {AdHocCommands} el
* @param {AdHocCommandUIProps} command
*/
export default (el, command) => html`
<li class="room-item list-group-item">
<div class="available-chatroom d-flex flex-row">
Expand Down
Loading

0 comments on commit 7aca70f

Please sign in to comment.