mirror of
https://github.com/zadam/trilium.git
synced 2025-06-06 18:08:33 +02:00
basic interactivity of search definition actions
This commit is contained in:
parent
5bb490e1ff
commit
3fa2535862
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user