mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 10:26:08 +01:00 
			
		
		
		
	fixes in attribute persistence + WIP on display of promoted attrs
This commit is contained in:
		| @@ -9,8 +9,6 @@ class ApiToken extends Entity { | |||||||
|     static get hashedProperties() { return ["apiTokenId", "token", "dateCreated", "isDeleted"]; } |     static get hashedProperties() { return ["apiTokenId", "token", "dateCreated", "isDeleted"]; } | ||||||
|  |  | ||||||
|     beforeSaving() { |     beforeSaving() { | ||||||
|         super.beforeSaving(); |  | ||||||
|  |  | ||||||
|         if (!this.isDeleted) { |         if (!this.isDeleted) { | ||||||
|             this.isDeleted = false; |             this.isDeleted = false; | ||||||
|         } |         } | ||||||
| @@ -18,6 +16,8 @@ class ApiToken extends Entity { | |||||||
|         if (!this.dateCreated) { |         if (!this.dateCreated) { | ||||||
|             this.dateCreated = dateUtils.nowDate(); |             this.dateCreated = dateUtils.nowDate(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         super.beforeSaving(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -10,13 +10,24 @@ class Attribute extends Entity { | |||||||
|     static get primaryKeyName() { return "attributeId"; } |     static get primaryKeyName() { return "attributeId"; } | ||||||
|     static get hashedProperties() { return ["attributeId", "noteId", "type", "name", "value", "isInheritable", "dateModified", "dateCreated"]; } |     static get hashedProperties() { return ["attributeId", "noteId", "type", "name", "value", "isInheritable", "dateModified", "dateCreated"]; } | ||||||
|  |  | ||||||
|  |     constructor(row) { | ||||||
|  |         super(row); | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             this.value = JSON.parse(this.value); | ||||||
|  |         } | ||||||
|  |         catch(e) {} | ||||||
|  |     } | ||||||
|  |  | ||||||
|     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]); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     async beforeSaving() { |     isDefinition() { | ||||||
|         super.beforeSaving(); |         return this.type === 'label' || this.type === 'relation'; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async beforeSaving() { | ||||||
|         if (!this.value) { |         if (!this.value) { | ||||||
|             // null value isn't allowed |             // null value isn't allowed | ||||||
|             this.value = ""; |             this.value = ""; | ||||||
| @@ -39,6 +50,8 @@ class Attribute extends Entity { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         this.dateModified = dateUtils.nowDate(); |         this.dateModified = dateUtils.nowDate(); | ||||||
|  |  | ||||||
|  |         super.beforeSaving(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -16,8 +16,6 @@ class Branch extends Entity { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     async beforeSaving() { |     async beforeSaving() { | ||||||
|         super.beforeSaving(); |  | ||||||
|  |  | ||||||
|         if (this.notePosition === undefined) { |         if (this.notePosition === undefined) { | ||||||
|             const maxNotePos = await sql.getValue('SELECT MAX(notePosition) FROM branches WHERE parentNoteId = ? AND isDeleted = 0', [this.parentNoteId]); |             const maxNotePos = await sql.getValue('SELECT MAX(notePosition) FROM branches WHERE parentNoteId = ? AND isDeleted = 0', [this.parentNoteId]); | ||||||
|             this.notePosition = maxNotePos === null ? 0 : maxNotePos + 1; |             this.notePosition = maxNotePos === null ? 0 : maxNotePos + 1; | ||||||
| @@ -32,6 +30,8 @@ class Branch extends Entity { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         this.dateModified = dateUtils.nowDate(); |         this.dateModified = dateUtils.nowDate(); | ||||||
|  |  | ||||||
|  |         super.beforeSaving(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -9,8 +9,6 @@ class Image extends Entity { | |||||||
|     static get hashedProperties() { return ["imageId", "format", "checksum", "name", "isDeleted", "dateModified", "dateCreated"]; } |     static get hashedProperties() { return ["imageId", "format", "checksum", "name", "isDeleted", "dateModified", "dateCreated"]; } | ||||||
|  |  | ||||||
|     beforeSaving() { |     beforeSaving() { | ||||||
|         super.beforeSaving(); |  | ||||||
|  |  | ||||||
|         if (!this.isDeleted) { |         if (!this.isDeleted) { | ||||||
|             this.isDeleted = false; |             this.isDeleted = false; | ||||||
|         } |         } | ||||||
| @@ -20,6 +18,8 @@ class Image extends Entity { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         this.dateModified = dateUtils.nowDate(); |         this.dateModified = dateUtils.nowDate(); | ||||||
|  |  | ||||||
|  |         super.beforeSaving(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -15,8 +15,6 @@ class Label extends Entity { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     async beforeSaving() { |     async beforeSaving() { | ||||||
|         super.beforeSaving(); |  | ||||||
|  |  | ||||||
|         if (!this.value) { |         if (!this.value) { | ||||||
|             // null value isn't allowed |             // null value isn't allowed | ||||||
|             this.value = ""; |             this.value = ""; | ||||||
| @@ -35,6 +33,8 @@ class Label extends Entity { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         this.dateModified = dateUtils.nowDate(); |         this.dateModified = dateUtils.nowDate(); | ||||||
|  |  | ||||||
|  |         super.beforeSaving(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -18,8 +18,6 @@ class NoteImage extends Entity { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     beforeSaving() { |     beforeSaving() { | ||||||
|         super.beforeSaving(); |  | ||||||
|  |  | ||||||
|         if (!this.isDeleted) { |         if (!this.isDeleted) { | ||||||
|             this.isDeleted = false; |             this.isDeleted = false; | ||||||
|         } |         } | ||||||
| @@ -29,6 +27,8 @@ class NoteImage extends Entity { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         this.dateModified = dateUtils.nowDate(); |         this.dateModified = dateUtils.nowDate(); | ||||||
|  |  | ||||||
|  |         super.beforeSaving(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -22,11 +22,11 @@ class NoteRevision extends Entity { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     beforeSaving() { |     beforeSaving() { | ||||||
|         super.beforeSaving(); |  | ||||||
|  |  | ||||||
|         if (this.isProtected) { |         if (this.isProtected) { | ||||||
|             protectedSessionService.encryptNoteRevision(this); |             protectedSessionService.encryptNoteRevision(this); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         super.beforeSaving(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -9,9 +9,9 @@ class Option extends Entity { | |||||||
|     static get hashedProperties() { return ["name", "value"]; } |     static get hashedProperties() { return ["name", "value"]; } | ||||||
|  |  | ||||||
|     beforeSaving() { |     beforeSaving() { | ||||||
|         super.beforeSaving(); |  | ||||||
|  |  | ||||||
|         this.dateModified = dateUtils.nowDate(); |         this.dateModified = dateUtils.nowDate(); | ||||||
|  |  | ||||||
|  |         super.beforeSaving(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -9,8 +9,6 @@ class RecentNote extends Entity { | |||||||
|     static get hashedProperties() { return ["branchId", "notePath", "dateCreated", "isDeleted"]; } |     static get hashedProperties() { return ["branchId", "notePath", "dateCreated", "isDeleted"]; } | ||||||
|  |  | ||||||
|     beforeSaving() { |     beforeSaving() { | ||||||
|         super.beforeSaving(); |  | ||||||
|  |  | ||||||
|         if (!this.isDeleted) { |         if (!this.isDeleted) { | ||||||
|             this.isDeleted = false; |             this.isDeleted = false; | ||||||
|         } |         } | ||||||
| @@ -18,6 +16,8 @@ class RecentNote extends Entity { | |||||||
|         if (!this.dateCreated) { |         if (!this.dateCreated) { | ||||||
|             this.dateCreated = dateUtils.nowDate(); |             this.dateCreated = dateUtils.nowDate(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         super.beforeSaving(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -19,8 +19,6 @@ class Relation extends Entity { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     async beforeSaving() { |     async beforeSaving() { | ||||||
|         super.beforeSaving(); |  | ||||||
|  |  | ||||||
|         if (this.position === undefined) { |         if (this.position === undefined) { | ||||||
|             this.position = 1 + await sql.getValue(`SELECT COALESCE(MAX(position), 0) FROM relations WHERE sourceNoteId = ?`, [this.sourceNoteId]); |             this.position = 1 + await sql.getValue(`SELECT COALESCE(MAX(position), 0) FROM relations WHERE sourceNoteId = ?`, [this.sourceNoteId]); | ||||||
|         } |         } | ||||||
| @@ -38,6 +36,8 @@ class Relation extends Entity { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         this.dateModified = dateUtils.nowDate(); |         this.dateModified = dateUtils.nowDate(); | ||||||
|  |  | ||||||
|  |         super.beforeSaving(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -22,10 +22,10 @@ function AttributesModel() { | |||||||
|  |  | ||||||
|     this.availableLabelTypes = [ |     this.availableLabelTypes = [ | ||||||
|         { text: "Text", value: "text" }, |         { text: "Text", value: "text" }, | ||||||
|         { text: "Integer", value: "integer" }, |         { text: "Number", value: "number" }, | ||||||
|         { text: "Decimal", value: "decimal" }, |  | ||||||
|         { text: "Boolean", value: "boolean" }, |         { text: "Boolean", value: "boolean" }, | ||||||
|         { text: "Date", value: "date" } |         { text: "Date", value: "date" }, | ||||||
|  |         { text: "DateTime", value: "datetime" } | ||||||
|     ]; |     ]; | ||||||
|  |  | ||||||
|     this.multiplicityTypes = [ |     this.multiplicityTypes = [ | ||||||
| @@ -57,15 +57,17 @@ function AttributesModel() { | |||||||
|         for (const attr of attributes) { |         for (const attr of attributes) { | ||||||
|             attr.labelValue = attr.type === 'label' ? attr.value : ''; |             attr.labelValue = attr.type === 'label' ? attr.value : ''; | ||||||
|             attr.relationValue = attr.type === 'relation' ? attr.value : ''; |             attr.relationValue = attr.type === 'relation' ? attr.value : ''; | ||||||
|             attr.labelDefinition = (attr.type === 'label-definition' && attr.value) ? JSON.parse(attr.value) : { |             attr.labelDefinition = (attr.type === 'label-definition' && attr.value) ? attr.value : { | ||||||
|                 labelType: "text", |                 labelType: "text", | ||||||
|                 multiplicityType: "singlevalue", |                 multiplicityType: "singlevalue", | ||||||
|                 isPromoted: true |                 isPromoted: true | ||||||
|             }; |             }; | ||||||
|             attr.relationDefinition = (attr.type === 'relation-definition' && attr.value) ? JSON.parse(attr.value) : { |             attr.relationDefinition = attr.type === ('relation-definition' && attr.value) ? attr.value : { | ||||||
|                 multiplicityType: "singlevalue", |                 multiplicityType: "singlevalue", | ||||||
|                 isPromoted: true |                 isPromoted: true | ||||||
|             }; |             }; | ||||||
|  |  | ||||||
|  |             delete attr.value; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         self.attributes(attributes.map(ko.observable)); |         self.attributes(attributes.map(ko.observable)); | ||||||
| @@ -140,10 +142,10 @@ function AttributesModel() { | |||||||
|                 attr.value = attr.relationValue; |                 attr.value = attr.relationValue; | ||||||
|             } |             } | ||||||
|             else if (attr.type === 'label-definition') { |             else if (attr.type === 'label-definition') { | ||||||
|                 attr.value = JSON.stringify(attr.labelDefinition); |                 attr.value = attr.labelDefinition; | ||||||
|             } |             } | ||||||
|             else if (attr.type === 'relation-definition') { |             else if (attr.type === 'relation-definition') { | ||||||
|                 attr.value = JSON.stringify(attr.relationDefinition); |                 attr.value = attr.relationDefinition; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             delete attr.labelValue; |             delete attr.labelValue; | ||||||
| @@ -158,11 +160,7 @@ function AttributesModel() { | |||||||
|  |  | ||||||
|         infoService.showMessage("Attributes have been saved."); |         infoService.showMessage("Attributes have been saved."); | ||||||
|  |  | ||||||
|         // FIXME FIXME FIXME FIXME FIXME |         noteDetailService.loadAttributes(); | ||||||
|         // FIXME FIXME FIXME FIXME FIXME |  | ||||||
|         // FIXME FIXME FIXME FIXME FIXME |  | ||||||
|         // FIXME FIXME FIXME FIXME FIXME |  | ||||||
|         //noteDetailService.loadAttributeList(); |  | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     function addLastEmptyRow() { |     function addLastEmptyRow() { | ||||||
|   | |||||||
| @@ -32,6 +32,7 @@ const $relationList = $("#relation-list"); | |||||||
| const $relationListInner = $("#relation-list-inner"); | const $relationListInner = $("#relation-list-inner"); | ||||||
| const $childrenOverview = $("#children-overview"); | const $childrenOverview = $("#children-overview"); | ||||||
| const $scriptArea = $("#note-detail-script-area"); | const $scriptArea = $("#note-detail-script-area"); | ||||||
|  | const $promotedAttributes = $("#note-detail-promoted-attributes"); | ||||||
|  |  | ||||||
| let currentNote = null; | let currentNote = null; | ||||||
|  |  | ||||||
| @@ -193,6 +194,8 @@ async function loadNoteDetail(noteId) { | |||||||
|     $scriptArea.html(''); |     $scriptArea.html(''); | ||||||
|  |  | ||||||
|     await bundleService.executeRelationBundles(getCurrentNote(), 'runOnNoteView'); |     await bundleService.executeRelationBundles(getCurrentNote(), 'runOnNoteView'); | ||||||
|  |  | ||||||
|  |     await loadAttributes(); | ||||||
| } | } | ||||||
|  |  | ||||||
| async function showChildrenOverview(hideChildrenOverview) { | async function showChildrenOverview(hideChildrenOverview) { | ||||||
| @@ -220,6 +223,39 @@ async function showChildrenOverview(hideChildrenOverview) { | |||||||
|     $childrenOverview.show(); |     $childrenOverview.show(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | async function loadAttributes() { | ||||||
|  |     $promotedAttributes.empty(); | ||||||
|  |  | ||||||
|  |     const noteId = getCurrentNoteId(); | ||||||
|  |  | ||||||
|  |     const attributes = await server.get('notes/' + noteId + '/attributes'); | ||||||
|  |  | ||||||
|  |     console.log(attributes); | ||||||
|  |  | ||||||
|  |     const promoted = attributes.filter(attr => (attr.type === 'label-definition' || attr.type === 'relation-definition') && attr.value.isPromoted); | ||||||
|  |  | ||||||
|  |     let idx = 1; | ||||||
|  |  | ||||||
|  |     if (promoted.length > 0) { | ||||||
|  |         for (const promotedAttr of promoted) { | ||||||
|  |             if (promotedAttr.type === 'label-definition') { | ||||||
|  |                 const inputId = "promoted-input-" + idx; | ||||||
|  |                 const $div = $("<div>").addClass("class", "form-group"); | ||||||
|  |                 const $label = $("<label>").prop("for", inputId).append(promotedAttr.name); | ||||||
|  |                 const $input = $("<input>") | ||||||
|  |                     .prop("id", inputId) | ||||||
|  |                     .prop("attribute-id", promotedAttr.attributeId) | ||||||
|  |                     .addClass("form-control") | ||||||
|  |                     .addClass("promoted-attribute-input"); | ||||||
|  |  | ||||||
|  |                 $div.append($label).append($input); | ||||||
|  |  | ||||||
|  |                 $promotedAttributes.append($div); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| async function loadLabelList() { | async function loadLabelList() { | ||||||
|     const noteId = getCurrentNoteId(); |     const noteId = getCurrentNoteId(); | ||||||
|  |  | ||||||
| @@ -312,6 +348,7 @@ export default { | |||||||
|     getCurrentNoteId, |     getCurrentNoteId, | ||||||
|     newNoteCreated, |     newNoteCreated, | ||||||
|     focus, |     focus, | ||||||
|  |     loadAttributes, | ||||||
|     loadLabelList, |     loadLabelList, | ||||||
|     loadRelationList, |     loadRelationList, | ||||||
|     saveNote, |     saveNote, | ||||||
|   | |||||||
| @@ -5,10 +5,53 @@ const attributeService = require('../../services/attributes'); | |||||||
| const repository = require('../../services/repository'); | const repository = require('../../services/repository'); | ||||||
| const Attribute = require('../../entities/attribute'); | const Attribute = require('../../entities/attribute'); | ||||||
|  |  | ||||||
| async function getNoteAttributes(req) { | async function getEffectiveNoteAttributes(req) { | ||||||
|     const noteId = req.params.noteId; |     const noteId = req.params.noteId; | ||||||
|  |  | ||||||
|     return await repository.getEntities("SELECT * FROM attributes WHERE isDeleted = 0 AND noteId = ? ORDER BY position, dateCreated", [noteId]); |     const attributes = await repository.getEntities(` | ||||||
|  |         WITH RECURSIVE tree(noteId, level) AS ( | ||||||
|  |         SELECT ?, 0 | ||||||
|  |             UNION | ||||||
|  |             SELECT branches.parentNoteId, tree.level + 1 FROM branches | ||||||
|  |             JOIN tree ON branches.noteId = tree.noteId | ||||||
|  |             JOIN notes ON notes.noteId = branches.parentNoteId | ||||||
|  |             WHERE notes.isDeleted = 0 AND branches.isDeleted = 0 | ||||||
|  |         ) | ||||||
|  |         SELECT attributes.* FROM attributes JOIN tree ON attributes.noteId = tree.noteId  | ||||||
|  |         WHERE attributes.isDeleted = 0 AND (attributes.isInheritable = 1 OR attributes.noteId = ?) | ||||||
|  |         ORDER BY level, noteId, position`, [noteId, noteId]); | ||||||
|  |         // attributes are ordered so that "closest" attributes are first | ||||||
|  |         // we order by noteId so that attributes from same note stay together. Actual noteId ordering doesn't matter. | ||||||
|  |  | ||||||
|  |     const filteredAttributes = attributes.filter((attr, index) => { | ||||||
|  |         if (attr.isDefinition()) { | ||||||
|  |             const firstDefinitionIndex = attributes.findIndex(el => el.type === attr.type && el.name === attr.name); | ||||||
|  |  | ||||||
|  |             // keep only if this element is the first definition for this type & name | ||||||
|  |             return firstDefinitionIndex === index; | ||||||
|  |         } | ||||||
|  |         else { | ||||||
|  |             const definitionAttr = attributes.find(el => el.type === attr.type + '-definition' && el.name === attr.name); | ||||||
|  |  | ||||||
|  |             if (!definitionAttr) { | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             const definition = definitionAttr.value; | ||||||
|  |  | ||||||
|  |             if (definition.multiplicityType === 'multivalue') { | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  |             else { | ||||||
|  |                 const firstAttrIndex = attributes.findIndex(el => el.type === attr.type && el.name === attr.name); | ||||||
|  |  | ||||||
|  |                 // in case of single-valued attribute we'll keep it only if it's first (closest) | ||||||
|  |                 return firstAttrIndex === index; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     return filteredAttributes; | ||||||
| } | } | ||||||
|  |  | ||||||
| async function updateNoteAttributes(req) { | async function updateNoteAttributes(req) { | ||||||
| @@ -38,6 +81,8 @@ async function updateNoteAttributes(req) { | |||||||
|         attributeEntity.isInheritable = attribute.isInheritable; |         attributeEntity.isInheritable = attribute.isInheritable; | ||||||
|         attributeEntity.isDeleted = attribute.isDeleted; |         attributeEntity.isDeleted = attribute.isDeleted; | ||||||
|  |  | ||||||
|  |         console.log("ATTR: ", attributeEntity); | ||||||
|  |  | ||||||
|         await attributeEntity.save(); |         await attributeEntity.save(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -58,8 +103,8 @@ async function getValuesForAttribute(req) { | |||||||
| } | } | ||||||
|  |  | ||||||
| module.exports = { | module.exports = { | ||||||
|     getNoteAttributes, |  | ||||||
|     updateNoteAttributes, |     updateNoteAttributes, | ||||||
|     getAttributeNames, |     getAttributeNames, | ||||||
|     getValuesForAttribute |     getValuesForAttribute, | ||||||
|  |     getEffectiveNoteAttributes | ||||||
| }; | }; | ||||||
| @@ -134,7 +134,7 @@ function register(app) { | |||||||
|  |  | ||||||
|     route(GET, '/api/notes/:noteId/download', [auth.checkApiAuthOrElectron], filesRoute.downloadFile); |     route(GET, '/api/notes/:noteId/download', [auth.checkApiAuthOrElectron], filesRoute.downloadFile); | ||||||
|  |  | ||||||
|     apiRoute(GET, '/api/notes/:noteId/attributes', attributesRoute.getNoteAttributes); |     apiRoute(GET, '/api/notes/:noteId/attributes', attributesRoute.getEffectiveNoteAttributes); | ||||||
|     apiRoute(PUT, '/api/notes/:noteId/attributes', attributesRoute.updateNoteAttributes); |     apiRoute(PUT, '/api/notes/:noteId/attributes', attributesRoute.updateNoteAttributes); | ||||||
|     apiRoute(GET, '/api/attributes/names', attributesRoute.getAttributeNames); |     apiRoute(GET, '/api/attributes/names', attributesRoute.getAttributeNames); | ||||||
|     apiRoute(GET, '/api/attributes/values/:attributeName', attributesRoute.getValuesForAttribute); |     apiRoute(GET, '/api/attributes/values/:attributeName', attributesRoute.getValuesForAttribute); | ||||||
|   | |||||||
| @@ -62,6 +62,12 @@ async function updateEntity(entity) { | |||||||
|  |  | ||||||
|     delete clone.jsonContent; |     delete clone.jsonContent; | ||||||
|  |  | ||||||
|  |     for (const key in clone) { | ||||||
|  |         if (clone[key] !== null && typeof clone[key] === 'object') { | ||||||
|  |             clone[key] = JSON.stringify(clone[key]); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     await sql.transactional(async () => { |     await sql.transactional(async () => { | ||||||
|         await sql.replace(entity.constructor.tableName, clone); |         await sql.replace(entity.constructor.tableName, clone); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -183,6 +183,8 @@ | |||||||
|       <div id="note-detail-wrapper"> |       <div id="note-detail-wrapper"> | ||||||
|         <div id="note-detail-script-area"></div> |         <div id="note-detail-script-area"></div> | ||||||
|  |  | ||||||
|  |         <div id="note-detail-promoted-attributes"></div> | ||||||
|  |  | ||||||
|         <div id="note-detail-component-wrapper"> |         <div id="note-detail-component-wrapper"> | ||||||
|           <div id="note-detail-text" class="note-detail-component" tabindex="2"></div> |           <div id="note-detail-text" class="note-detail-component" tabindex="2"></div> | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user