mirror of
https://github.com/zadam/trilium.git
synced 2025-06-06 18:08:33 +02:00
work in progress on attributes UI - unification of labels and relations now mostly works
This commit is contained in:
parent
509093b755
commit
61987e46f7
1
db/migrations/0110__add_isInheritable_to_attributes.sql
Normal file
1
db/migrations/0110__add_isInheritable_to_attributes.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE attributes ADD isInheritable int DEFAULT 0 NULL;
|
@ -8,7 +8,7 @@ const sql = require('../services/sql');
|
|||||||
class Attribute extends Entity {
|
class Attribute extends Entity {
|
||||||
static get tableName() { return "attributes"; }
|
static get tableName() { return "attributes"; }
|
||||||
static get primaryKeyName() { return "attributeId"; }
|
static get primaryKeyName() { return "attributeId"; }
|
||||||
static get hashedProperties() { return ["attributeId", "noteId", "type", "name", "value", "dateModified", "dateCreated"]; }
|
static get hashedProperties() { return ["attributeId", "noteId", "type", "name", "value", "isInheritable", "dateModified", "dateCreated"]; }
|
||||||
|
|
||||||
async getNote() {
|
async getNote() {
|
||||||
return await repository.getEntity("SELECT * FROM notes WHERE noteId = ?", [this.noteId]);
|
return await repository.getEntity("SELECT * FROM notes WHERE noteId = ?", [this.noteId]);
|
||||||
@ -26,6 +26,10 @@ class Attribute extends Entity {
|
|||||||
this.position = 1 + await sql.getValue(`SELECT COALESCE(MAX(position), 0) FROM attributes WHERE noteId = ?`, [this.noteId]);
|
this.position = 1 + await sql.getValue(`SELECT COALESCE(MAX(position), 0) FROM attributes WHERE noteId = ?`, [this.noteId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this.isInheritable) {
|
||||||
|
this.isInheritable = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.isDeleted) {
|
if (!this.isDeleted) {
|
||||||
this.isDeleted = false;
|
this.isDeleted = false;
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,10 @@ function AttributesModel() {
|
|||||||
{ text: "Relation", value: "relation" }
|
{ text: "Relation", value: "relation" }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
this.typeChanged = function(data, event) {
|
||||||
|
self.getTargetAttribute(event.target).valueHasMutated();
|
||||||
|
};
|
||||||
|
|
||||||
this.updateAttributePositions = function() {
|
this.updateAttributePositions = function() {
|
||||||
let position = 0;
|
let position = 0;
|
||||||
|
|
||||||
@ -36,6 +40,13 @@ function AttributesModel() {
|
|||||||
|
|
||||||
const attributes = await server.get('notes/' + noteId + '/attributes');
|
const attributes = await server.get('notes/' + noteId + '/attributes');
|
||||||
|
|
||||||
|
for (const attr of attributes) {
|
||||||
|
attr.labelValue = attr.type === 'label' ? attr.value : '';
|
||||||
|
attr.relationValue = attr.type === 'relation' ? attr.value : '';
|
||||||
|
|
||||||
|
delete attr.value;
|
||||||
|
}
|
||||||
|
|
||||||
self.attributes(attributes.map(ko.observable));
|
self.attributes(attributes.map(ko.observable));
|
||||||
|
|
||||||
addLastEmptyRow();
|
addLastEmptyRow();
|
||||||
@ -107,12 +118,14 @@ function AttributesModel() {
|
|||||||
const attributes = self.attributes().filter(attr => attr().isDeleted === 0);
|
const attributes = self.attributes().filter(attr => attr().isDeleted === 0);
|
||||||
const last = attributes.length === 0 ? null : attributes[attributes.length - 1]();
|
const last = attributes.length === 0 ? null : attributes[attributes.length - 1]();
|
||||||
|
|
||||||
if (!last || last.name.trim() !== "" || last.value !== "") {
|
if (!last || last.name.trim() !== "") {
|
||||||
self.attributes.push(ko.observable({
|
self.attributes.push(ko.observable({
|
||||||
attributeId: '',
|
attributeId: '',
|
||||||
type: 'label',
|
type: 'label',
|
||||||
name: '',
|
name: '',
|
||||||
value: '',
|
labelValue: '',
|
||||||
|
relationValue: '',
|
||||||
|
isInheritable: false,
|
||||||
isDeleted: 0,
|
isDeleted: 0,
|
||||||
position: 0
|
position: 0
|
||||||
}));
|
}));
|
||||||
@ -148,7 +161,7 @@ function AttributesModel() {
|
|||||||
this.isEmptyName = function(index) {
|
this.isEmptyName = function(index) {
|
||||||
const cur = self.attributes()[index]();
|
const cur = self.attributes()[index]();
|
||||||
|
|
||||||
return cur.name.trim() === "" && (cur.attributeId !== "" || cur.value !== "");
|
return cur.name.trim() === "" && (cur.attributeId !== "" || cur.labelValue !== "" || cur.relationValue);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.getTargetAttribute = function(target) {
|
this.getTargetAttribute = function(target) {
|
||||||
@ -204,7 +217,7 @@ $dialog.on('focus', '.attribute-name', function (e) {
|
|||||||
$(this).autocomplete("search", $(this).val());
|
$(this).autocomplete("search", $(this).val());
|
||||||
});
|
});
|
||||||
|
|
||||||
$dialog.on('focus', '.attribute-value', async function (e) {
|
$dialog.on('focus', '.label-value', async function (e) {
|
||||||
if (!$(this).hasClass("ui-autocomplete-input")) {
|
if (!$(this).hasClass("ui-autocomplete-input")) {
|
||||||
const attributeName = $(this).parent().parent().find('.attribute-name').val();
|
const attributeName = $(this).parent().parent().find('.attribute-name').val();
|
||||||
|
|
||||||
@ -234,6 +247,49 @@ $dialog.on('focus', '.attribute-value', async function (e) {
|
|||||||
$(this).autocomplete("search", $(this).val());
|
$(this).autocomplete("search", $(this).val());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
async function initNoteAutocomplete($el) {
|
||||||
|
if (!$el.hasClass("ui-autocomplete-input")) {
|
||||||
|
await $el.autocomplete({
|
||||||
|
source: async function (request, response) {
|
||||||
|
const result = await server.get('autocomplete?query=' + encodeURIComponent(request.term));
|
||||||
|
|
||||||
|
if (result.length > 0) {
|
||||||
|
response(result.map(row => {
|
||||||
|
return {
|
||||||
|
label: row.label,
|
||||||
|
value: row.label + ' (' + row.value + ')'
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
response([{
|
||||||
|
label: "No results",
|
||||||
|
value: "No results"
|
||||||
|
}]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
minLength: 0,
|
||||||
|
select: function (event, ui) {
|
||||||
|
if (ui.item.value === 'No results') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$dialog.on('focus', '.relation-target-note-id', async function () {
|
||||||
|
await initNoteAutocomplete($(this));
|
||||||
|
});
|
||||||
|
|
||||||
|
$dialog.on('click', '.relations-show-recent-notes', async function () {
|
||||||
|
const $autocomplete = $(this).parent().find('.relation-target-note-id');
|
||||||
|
|
||||||
|
await initNoteAutocomplete($autocomplete);
|
||||||
|
|
||||||
|
$autocomplete.autocomplete("search", "");
|
||||||
|
});
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
showDialog
|
showDialog
|
||||||
};
|
};
|
@ -3,7 +3,7 @@
|
|||||||
const build = require('./build');
|
const build = require('./build');
|
||||||
const packageJson = require('../../package');
|
const packageJson = require('../../package');
|
||||||
|
|
||||||
const APP_DB_VERSION = 109;
|
const APP_DB_VERSION = 110;
|
||||||
const SYNC_VERSION = 1;
|
const SYNC_VERSION = 1;
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
@ -40,7 +40,7 @@ async function load() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function findNotes(query) {
|
function findNotes(query) {
|
||||||
if (!noteTitles || query.length <= 2) {
|
if (!noteTitles || !query.length) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -567,13 +567,15 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th></th>
|
<th></th>
|
||||||
<th>ID</th>
|
<th>ID</th>
|
||||||
|
<th>Type</th>
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
<th>Value</th>
|
<th>Value</th>
|
||||||
|
<th>Inheritable</th>
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody data-bind="foreach: attributes">
|
<tbody data-bind="foreach: attributes">
|
||||||
<tr data-bind="if: isDeleted == 0">
|
<tr data-bind="if: isDeleted == 0" class="attribute-row">
|
||||||
<td class="handle">
|
<td class="handle">
|
||||||
<span class="glyphicon glyphicon-resize-vertical"></span>
|
<span class="glyphicon glyphicon-resize-vertical"></span>
|
||||||
<input type="hidden" name="position" data-bind="value: position"/>
|
<input type="hidden" name="position" data-bind="value: position"/>
|
||||||
@ -581,7 +583,7 @@
|
|||||||
<!-- ID column has specific width because if it's empty its size can be deformed when dragging -->
|
<!-- ID column has specific width because if it's empty its size can be deformed when dragging -->
|
||||||
<td data-bind="text: attributeId" style="min-width: 10em; font-size: smaller;"></td>
|
<td data-bind="text: attributeId" style="min-width: 10em; font-size: smaller;"></td>
|
||||||
<td>
|
<td>
|
||||||
<select data-bind="options: $root.availableTypes, optionsText: 'text', optionsValue: 'value', value: type"></select>
|
<select data-bind="options: $parent.availableTypes, optionsText: 'text', optionsValue: 'value', value: type, event: { change: $parent.typeChanged }"></select>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<!-- Change to valueUpdate: blur is necessary because jQuery UI autocomplete hijacks change event -->
|
<!-- Change to valueUpdate: blur is necessary because jQuery UI autocomplete hijacks change event -->
|
||||||
@ -590,7 +592,19 @@
|
|||||||
<div style="color: red" data-bind="if: $parent.isEmptyName($index())">Attribute name can't be empty.</div>
|
<div style="color: red" data-bind="if: $parent.isEmptyName($index())">Attribute name can't be empty.</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" class="attribute-value form-control" data-bind="value: value, valueUpdate: 'blur', event: { blur: $parent.attributeChanged }" style="width: 300px"/>
|
<input type="text" class="label-value form-control" data-bind="visible: type == 'label', value: labelValue, valueUpdate: 'blur', event: { blur: $parent.attributeChanged }" style="width: 300px"/>
|
||||||
|
|
||||||
|
<div class="relation-value input-group" data-bind="visible: type == 'relation'">
|
||||||
|
<input class="form-control relation-target-note-id"
|
||||||
|
placeholder="search for note by its name"
|
||||||
|
data-bind="value: relationValue, valueUpdate: 'blur', event: { blur: $parent.attributeChanged }"
|
||||||
|
style="width: 300px;">
|
||||||
|
|
||||||
|
<span class="input-group-addon relations-show-recent-notes" title="Show recent notes" style="background: url('/images/icons/clock-16.png') no-repeat center; cursor: pointer;"></span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td title="Inheritable relations are automatically inherited to the child notes">
|
||||||
|
<input type="checkbox" value="1" data-bind="checked: isInheritable" />
|
||||||
</td>
|
</td>
|
||||||
<td title="Delete" style="padding: 13px; cursor: pointer;">
|
<td title="Delete" style="padding: 13px; cursor: pointer;">
|
||||||
<span class="glyphicon glyphicon-trash" data-bind="click: $parent.deleteAttribute"></span>
|
<span class="glyphicon glyphicon-trash" data-bind="click: $parent.deleteAttribute"></span>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user