basic interactivity of search definition actions

This commit is contained in:
zadam 2021-01-17 23:01:01 +01:00
parent 5bb490e1ff
commit 3fa2535862
3 changed files with 143 additions and 59 deletions

View File

@ -87,17 +87,23 @@ const TPL = `
</button> </button>
<div class="dropdown" style="display: inline-block;"> <div class="dropdown" style="display: inline-block;">
<button class="btn btn-sm dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <button class="btn btn-sm dropdown-toggle action-add-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="bx bxs-zap"></span> <span class="bx bxs-zap"></span>
action action
</button> </button>
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton"> <div class="dropdown-menu">
<a class="dropdown-item" href="#">Delete note</a> <a class="dropdown-item" href="#" data-action-add="deleteNote">
<a class="dropdown-item" href="#">Delete attribute</a> Delete note</a>
<a class="dropdown-item" href="#">Rename attribute</a> <a class="dropdown-item" href="#" data-action-add="deleteAttribute">
<a class="dropdown-item" href="#">Change label value</a> Delete attribute</a>
<a class="dropdown-item" href="#">Change relation target</a> <a class="dropdown-item" href="#" data-action-add="renameAttribute">
<a class="dropdown-item" href="#">Execute script</a> Rename attribute</a>
<a class="dropdown-item" href="#" data-action-add="changeLabelValue">
Change label value</a>
<a class="dropdown-item" href="#" data-action-add="changeRelationTarget">
Change relation target</a>
<a class="dropdown-item" href="#" data-action-add="executeScript">
Execute script</a>
</div> </div>
</div> </div>
</td> </td>
@ -159,56 +165,78 @@ const TPL = `
</td> </td>
</tr> </tr>
</tbody> </tbody>
<tr> <tbody class="action-options">
<td colspan="2"> <tr>
<span class="bx bx-trash"></span> <td>
Rename attribute name:
Delete matched note </td>
</td> <td>
<td> <div style="display: flex; align-items: center">
<span class="bx bx-x icon-action"></span> <div style="margin-right: 15px;">From:</div>
</td>
</tr>
<tr>
<td>
Rename attribute name:
</td>
<td>
<div style="display: flex; align-items: center">
<div style="margin-right: 15px;">From:</div>
<input type="text" class="form-control" placeholder="old name"/>
<div style="margin-right: 15px; margin-left: 15px;">To:</div>
<input type="text" class="form-control" placeholder="new name"/>
</div>
</td>
<td>
<span class="bx bx-x icon-action"></span>
</td>
</tr>
<tr>
<td colspan="3">
<div style="display: flex; justify-content: space-evenly">
<button type="button" class="btn btn-sm">
<span class="bx bx-search"></span>
Search
<kbd>enter</kbd> <input type="text" class="form-control" placeholder="old name"/>
</button>
<div style="margin-right: 15px; margin-left: 15px;">To:</div>
<button type="button" class="btn btn-sm">
<span class="bx bxs-zap"></span> <input type="text" class="form-control" placeholder="new name"/>
Search & Execute actions </div>
</button> </td>
</div> <td>
</td> <span class="bx bx-x icon-action"></span>
</tr> </td>
</tr>
<tr>
<td colspan="3">
<div style="display: flex; justify-content: space-evenly">
<button type="button" class="btn btn-sm">
<span class="bx bx-search"></span>
Search
<kbd>enter</kbd>
</button>
<button type="button" class="btn btn-sm">
<span class="bx bxs-zap"></span>
Search & Execute actions
</button>
</div>
</td>
</tr>
</tbody>
</table> </table>
</div> </div>
</div>`; </div>`;
const ACTION_TPLS = {
deleteNote: `
<tr>
<td colspan="2">
<span class="bx bx-trash"></span>
Delete matched note
</td>
<td>
<span class="bx bx-x icon-action" data-action-conf-del></span>
</td>
</tr>`,
deleteAttribute: `
<tr>
<td>
Delete attribute:
</td>
<td>
<div style="display: flex; align-items: center">
<div style="margin-right: 15px;">Attribute name:</div>
<input type="text" class="form-control"/>
</div>
</td>
<td>
<span class="bx bx-x icon-action"></span>
</td>
</tr>`
};
export default class SearchDefinitionWidget extends TabAwareWidget { export default class SearchDefinitionWidget extends TabAwareWidget {
static getType() { return "search"; } static getType() { return "search"; }
@ -306,14 +334,40 @@ export default class SearchDefinitionWidget extends TabAwareWidget {
await this.setAttribute('label', 'orderDirection', orderDirection); await this.setAttribute('label', 'orderDirection', orderDirection);
}); });
this.$actionOptions = this.$widget.find('.action-options');
this.$widget.on('click', '[data-action-add]', async event => {
const actionName = $(event.target).attr('data-action-add');
await server.post(`notes/${this.noteId}/attributes`, {
type: 'label',
name: 'action',
value: JSON.stringify({
name: actionName
})
});
this.$widget.find('.action-add-toggle').dropdown('toggle');
await ws.waitForMaxKnownEntityChangeId();
this.refresh();
});
this.$widget.on('click', '[data-action-conf-del]', async event => {
const attributeId = $(event.target).closest('[data-attribute-id]').attr('data-attribute-id');
await server.remove(`notes/${this.noteId}/attributes/${attributeId}`);
await ws.waitForMaxKnownEntityChangeId();
this.refresh();
});
} }
async setAttribute(type, name, value = '') { async setAttribute(type, name, value = '') {
await server.put(`notes/${this.noteId}/set-attribute`, { await server.put(`notes/${this.noteId}/set-attribute`, { type, name, value });
type,
name,
value
});
await ws.waitForMaxKnownEntityChangeId(); await ws.waitForMaxKnownEntityChangeId();
} }
@ -340,12 +394,30 @@ export default class SearchDefinitionWidget extends TabAwareWidget {
.val(descendantOfNote ? descendantOfNote.title : "") .val(descendantOfNote ? descendantOfNote.title : "")
.setSelectedNotePath(descendantOfNoteId); .setSelectedNotePath(descendantOfNoteId);
if (note.hasLabel('orderBy')) { if (note.hasLabel('orderBy')) {
this.$orderBy.val(note.getLabelValue('orderBy')); this.$orderBy.val(note.getLabelValue('orderBy'));
this.$orderDirection.val(note.getLabelValue('orderDirection') || 'asc'); this.$orderDirection.val(note.getLabelValue('orderDirection') || 'asc');
} }
this.$actionOptions.empty();
for (const actionAttr of this.note.getLabels('action')) {
let actionDef;
try {
actionDef = JSON.parse(actionAttr.value);
}
catch (e) {
console.log(`Parsing of attribute: '${actionAttr.value}' failed with error: ${e.message}`);
continue;
}
const $actionConf = $(ACTION_TPLS[actionDef.name]);
$actionConf.attr('data-attribute-id', actionAttr.attributeId);
this.$actionOptions.append($actionConf);
}
this.refreshResults(); // important specifically when this search note was not yet refreshed this.refreshResults(); // important specifically when this search note was not yet refreshed
} }

View File

@ -86,6 +86,16 @@ function setNoteAttribute(req) {
attr.save(); attr.save();
} }
function addNoteAttribute(req) {
const noteId = req.params.noteId;
const body = req.body;
const attr = new Attribute(body);
attr.noteId = noteId;
attr.save();
}
function deleteNoteAttribute(req) { function deleteNoteAttribute(req) {
const noteId = req.params.noteId; const noteId = req.params.noteId;
const attributeId = req.params.attributeId; const attributeId = req.params.attributeId;
@ -220,6 +230,7 @@ module.exports = {
updateNoteAttributes, updateNoteAttributes,
updateNoteAttribute, updateNoteAttribute,
setNoteAttribute, setNoteAttribute,
addNoteAttribute,
deleteNoteAttribute, deleteNoteAttribute,
getAttributeNames, getAttributeNames,
getValuesForAttribute, getValuesForAttribute,

View File

@ -176,6 +176,7 @@ function register(app) {
apiRoute(POST, '/api/notes/:noteId/saveToTmpDir', filesRoute.saveToTmpDir); apiRoute(POST, '/api/notes/:noteId/saveToTmpDir', filesRoute.saveToTmpDir);
apiRoute(GET, '/api/notes/:noteId/attributes', attributesRoute.getEffectiveNoteAttributes); apiRoute(GET, '/api/notes/:noteId/attributes', attributesRoute.getEffectiveNoteAttributes);
apiRoute(POST, '/api/notes/:noteId/attributes', attributesRoute.addNoteAttribute);
apiRoute(PUT, '/api/notes/:noteId/attributes', attributesRoute.updateNoteAttributes); apiRoute(PUT, '/api/notes/:noteId/attributes', attributesRoute.updateNoteAttributes);
apiRoute(PUT, '/api/notes/:noteId/attribute', attributesRoute.updateNoteAttribute); apiRoute(PUT, '/api/notes/:noteId/attribute', attributesRoute.updateNoteAttribute);
apiRoute(PUT, '/api/notes/:noteId/set-attribute', attributesRoute.setNoteAttribute); apiRoute(PUT, '/api/notes/:noteId/set-attribute', attributesRoute.setNoteAttribute);