From 22f9efd58a9e42fb6e6b8fbf640cc4a18f214276 Mon Sep 17 00:00:00 2001 From: Charlie Humphreys Date: Wed, 17 Nov 2021 22:22:33 -0600 Subject: [PATCH 01/24] Update API to support homebrew tags #758 --- server/homebrew.api.js | 1 + server/homebrew.model.js | 20 +++++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 59d4f6d68..ffaf6e91f 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -76,6 +76,7 @@ const updateBrew = (req, res)=>{ const updateBrew = excludePropsFromUpdate(req.body); brew = _.merge(brew, updateBrew); brew.text = mergeBrewText(brew.text, brew.style); + brew.tags = updateBrew.tags; // Compress brew text to binary before saving brew.textBin = zlib.deflateRawSync(brew.text); diff --git a/server/homebrew.model.js b/server/homebrew.model.js index acc78a624..4de2b6510 100644 --- a/server/homebrew.model.js +++ b/server/homebrew.model.js @@ -12,7 +12,7 @@ const HomebrewSchema = mongoose.Schema({ pageCount : { type: Number, default: 1 }, description : { type: String, default: '' }, - tags : { type: String, default: '' }, + tags : [String], systems : [String], renderer : { type: String, default: '' }, authors : [String], @@ -66,6 +66,24 @@ HomebrewSchema.statics.getByUser = function(username, allowAccess=false){ const Homebrew = mongoose.model('Homebrew', HomebrewSchema); +Homebrew.count({ tags: '' }, async (err, count)=>{ + if(!err) { + if(count > 0) { + Homebrew.updateMany({ tags: '' }, { tags: [] }, { multi: true }, function(err, data) { + if(!err) { + console.log('Successfully updated all brews to new schema definition'); + } else { + console.log('An error occurred while updating brews to the new schema', err); + } + }); + } else { + console.log('No brews to update'); + } + } else { + console.log('An error occurred while counting brews with the old schema', err); + } +}); + module.exports = { schema : HomebrewSchema, model : Homebrew, From 330bf20d61c066ceaa98b06e18af6faa602aaae5 Mon Sep 17 00:00:00 2001 From: Charlie Humphreys Date: Wed, 17 Nov 2021 22:26:25 -0600 Subject: [PATCH 02/24] Update UI to support tags #758 --- .../editor/metadataEditor/metadataEditor.jsx | 101 ++++++++++++++++-- .../editor/metadataEditor/metadataEditor.less | 27 +++++ 2 files changed, 120 insertions(+), 8 deletions(-) diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index c7dea871b..4156bd3cc 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -1,3 +1,4 @@ +/* eslint-disable max-lines */ require('./metadataEditor.less'); const React = require('react'); const createClass = require('create-react-class'); @@ -14,7 +15,7 @@ const MetadataEditor = createClass({ editId : null, title : '', description : '', - tags : '', + tags : [], published : false, authors : [], systems : [], @@ -23,6 +24,38 @@ const MetadataEditor = createClass({ onChange : ()=>{} }; }, + getInitialState : function() { + return { + tagContext : !!this.props.metadata.tags ? this.props.metadata.tags.map((tag)=>({ + tag, + editing : false + })) : [], + temporaryTag : '', + updateTag : '' + }; + }, + + componentWillUpdate : function() { + const tags = this.props.metadata.tags; + if(!!tags) { + const contextTags = Object.values(this.state.tagContext).map((context)=>context.tag); + let updateContext = tags.length !== contextTags.length; + for (let i = 0; i < tags.length && updateContext === false; i++){ + const tag = tags[i]; + if(!contextTags.includes(tag)) + updateContext = true; + } + if(updateContext) { + this.setState((prevState)=>({ + ...prevState, + tagContext : this.props.metadata.tags.map((tag)=>({ + tag, + editing : false + })) + })); + } + } + }, handleFieldChange : function(name, e){ this.props.onChange(_.merge({}, this.props.metadata, { @@ -148,6 +181,63 @@ const MetadataEditor = createClass({ ; }, + addTag : function(tag){ + this.props.metadata.tags = _.uniq([...this.props.metadata.tags, tag]); + this.props.onChange(this.props.metadata); + }, + removeTag : function(tag){ + this.props.metadata.tags = this.props.metadata.tags.filter((t)=>t !== tag); + this.props.onChange(this.props.metadata); + }, + updateTag : function(tag, index){ + this.props.metadata.tags[index] = tag; + this.props.onChange(this.props.metadata); + }, + editTag : function(index){ + const tagContext = this.state.tagContext.map((context, i)=>{ + context.editing = index === i; + return context; + }); + this.setState({ tagContext, updateTag: this.props.metadata.tags[index] }); + }, + handleTagInputKeyDown : function(event, index){ + if(event.key === 'Enter') { + if(!!index) { + this.updateTag(event.target.value, index); + const tagContext = this.state.tagContext; + tagContext[index].editing = false; + this.setState({ tagContext, updateTag: '' }); + } else { + this.addTag(event.target.value); + this.setState({ temporaryTag: '' }); + } + } + }, + + renderTags : function(){ + const tagElements = Object.values(this.state.tagContext).map((context, i)=>context.editing + ? { this.handleTagInputKeyDown(e, i); }} + onChange={(e)=>{ this.setState({ updateTag: e.target.value }); }}/> + :
{ this.editTag(i); }}>{context.tag}  + this.removeTag(context.tag)}/> +
+ ); + + return
+ +
+ {tagElements} + { this.handleTagInputKeyDown(e); }} + onChange={(e)=>{ this.setState({ temporaryTag: e.target.value }); }}/> +
+
; + }, + render : function(){ return
@@ -161,13 +251,8 @@ const MetadataEditor = createClass({