Vue Tasks App
Vue implementation of the tasks app.
description
Learn vue and make a usable tasks app. It should implement most of gqueues functionality but with
- faster handling
- documentation in markdown
- links
- better priorities
investigation
So I want a detailed page with graphic support to be able to understand this later. Try to graphically explain any step you did or at least are going to do.
subtasks
Find a suitable picture
Since we are browsing for images anyway combine this with searching for good example picks.
This link is interesting for vue anyway, but also contains examples for annotated pictures.
https://medium.com/js-dojo/component-communication-in-vue-js-ca8b591d7efa
emit to parent
Document v-model
V-model seems to be just a shorthand for adding a prop (into the component) and a v-on: handler (out of the component)
But it seems it is always the input method .
So this :
This ends up (in the console debugger) as
[visit](StretchArea class="task-descr" modelValue="ddd\n \n " onUpdate:modelValue=fn )
So modelValue is the internal variable used for the content but also the handler for changing the content.
We better just assign input and output manually.
| better split data and handler | |
|---|---|
Note the v-bind
if you are wondering why you get the string ‘task.description’ in your component instead of the value, you forgot to put v-bind before the prop.
<StretchArea class="task-descr"
description="task.description"
@blur="updateText">
[visit](/StretchArea)
We had to do this for the StretchArea component to work
| actual StretchArea code | |
|---|---|
And the code for the component is below, note the prop is description and blur is an emitter that is called explicitly in the callback update_text. So you capture onblur here and then ‘trigger’ the onblur of the parent component yourself. Be sure to pass the data !
documentation solution
We should be able to click on a documentation button and have an editor popup to enter markdown. Solution we need to investigate:
But since we use mkdocs now, the markdown-it rendering is not so much of an issue, also it is part of the documentation project, not tasks. The main problem is entering and displaying markdown while editing and diamondfsd seems one of the candidates.
vuex getters
Getters are like computed state in vue
computed is a VUE property, not vuex.
So you can add a section in the store where you can construct a value rather than just returning the state.
firebase model
We recognize a number of data objects inside the tasks app..
- tasks : paint the fence
- topics : garden jobs
- groups : house
- layouts : priority list, tree
task
A task is a single piece of work and the endleaf of our trees.
- a caption : 1 line
- color : a string with name or hex value
- description : a multi line text describing the task better
- priority : a number
- status : done for instance
- tags : list of tags to add
- documents : a list of .md documents
- subtasks : a list of children
Maybe more, but at least we cannot present all data in the tree itself. For instance description and documents will make the tree data too big.
So there will be at least a tasks list in the database, identified by id that will be referenced from the tree structure.
A task tree is unlimited in levels and size. There is no root node, but rather an array of level 1 entries.
We have a tasktrees and a tasks collection in the app.
layout
A tree holds the data for the dragdrop trees for various components. Trees have a json format that HE-TREE-VUE can understand, mostly with 'caption', 'color' fields, etc. But trees can vary because they will be maintained by different components and in different database collections.
For now we recognize :
- task trees : right pane tree
- topic trees : left pane tree, 2 levels but free to edit
- sorted trees : display as a list, but draggable and sortable
- next trees : display next x entries of every topics as a 2 level tree
- tags tree : maybe later, like the tags in gqueues
From now we will call these arrangements: layout's
topic
Topics are groups of tasks, and these can also be hierarchical. However we keep a maximum level of 2, so that everything beneath that is a task + possible subtasks. For instance :
- uvt
- OWB
- BHV
- klopt
- task list
- planner
- house
House is divided into kitchen, bedroom etc, but that is resolved in subtasks. Every endpoint in the topic list is selectable and will load a complete task tree in the right/tasks tab.
We have a topictrees collection in the app, if we need a separate topics is not clear yet.
group
In gqueues they call this queue. It is the groups of trees in the left pane.
- topic trees
- sortable lists
- next lists
- tags
These will probably be hardcoded into separate components anyway ?!
The left pane will be something like this
- My Tasks (layout)
- uvt (group)
- owb (topic)
- bhv (topic)
- klopt(group)
- tasks (topic)
- home (topic)
- planner (topic)
- messy (group)
- uvt (group)
- priority lists
- uvt tasks
- owb
- bhv
- klopt tasks
- home
- planner
- tasklist
- tasks
- everything
- uvt
- klopt
- uvt tasks
- next lists
- everything
- uvt
- klopt
- uvt
- uvt
- klopt
- tasks
- everything
- tags
- tag1
- tag2
Depending on what you select in the leafs will change the right pane. A topictree does really different things than a next tree, so make all of them separate components.
The collections
topics : topictree, because the bulk of this tree is topics, only the root should says 'categories or groups' priorities : priority tree next : next tree tags : tag tree
If we look closer, all trees are roughly the same except for the handling and the data of each leaf. But fetching a tree, updating and adding a leaf is almost the same boilerplate code.
We have now split the store in different modules.
| Current Store | |
|---|---|
The topicstore is also namespaced, so for each tree there could be e different object maintained. This was born when we created the topicstore like this.
[visit](hr)
[visit](TopicTree group="categories"/)
[visit](hr)
[visit](TopicTree group="special"/)
So this meant group was a prop to the TopicTree and we address the store like this.
...
props: {
group: String,
value: String
},
...
methods: {
...
this.$store.dispatch(`${this.group}/fetchTopicTree`, this.group);
...
However, we decided to limit the trees to the list below, and also the store and databases collections.
- TopicTree : topicstore writing to "topictree" in the database
- TaskTree : taskstore writing to "tasktree" in the database
- SortTree : sort store, ...
- NextTree : next store,
- TagTree : tags tore
Maybe we can even combine the logic into a single store writing to different collections or even one big tree collection !.
First we need to fix this bug by removing the group prop and writing to TopicTree. This also means we don't have to registerModule() the group dynamically. I leave the beforeCreate method as an example of how it works.
beforeCreate() {
//this.$store.registerModule(this.group, TopicStore);
},
segment problem
Uncaught FirebaseError: Invalid document reference. Document references must have an even number of segments, but topictrees has 1
This is always a problem with the build-up of your documents in combination with the query. For instance, the next structure was built up earlier :

Now you see that it goes Collection -> Document -> Collection, where documents have a generated id, and collections have a name you provided.
This alternating continues if you keep adding one-to-many relations downward, sop this error says you are trying to access a document where a collection is expected or vice-versa.
Note that the above error says the document reference is 'topictrees' (, but topictrees has 1'. For deeper paths this would read something like
Document references must have an even number of segments, but topictrees/IZQynt1j4Zk0D8bPaDJU/something has 1.
So it says your path only has 1 segment topictrees and it should read 'topictrees/topics' as seen in the picture.
In short: I removed the extra name from this call
const docRefTree = doc(db, "topictrees");
// should be :
const docRefTree = doc(db, "topictrees", "topics");
component naming
This is for the overview, open in new tab to enlarge.
troubleshooting
Error messages and solutions.
[Vue warn]: Failed to resolve component: TopicBlock
If this is a native custom element, make sure to exclude it from component resolution via compilerOptions.isCustomElement.
Simple solution, add TopicBlock to the components object of the enclosing component.
bootstrap.css.map warning
DevTools failed to load source map: Could not load content for http://localhost:3000/bootstrap.css.map: HTTP error: status code 404, net::ERR_HTTP_RESPONSE_CODE_FAILURE
As this comment points out this is not an error saying the map file is not loaded.
.d-print-none {
display: none !important;
}
}
/*# sourceMappingURL=bootstrap.css.map */
So just delete it !. And also restart your ‘npm run dev’ server. The error will be gone!
unhandled error
This warning in the console got me searching much too long. If you try to follow the stack trace there is not one recognizable function, so heed this :
Just read the error itself !!!
value=undefined for the tasktree data !!
runtime-core.esm-bundler.js:38 [Vue warn]: Unhandled error during execution of render function
at [visit](Tree class="tasktree" value=undefined edgeScroll="" ... )
at [visit](TaskTree)
at [visit](Pane style= {height: '100%', overflow: 'visible'} )
at [visit](Splitpanes class="default-theme" vertical="" style= {height: '100%'} )
at [visit](App)
This happened after splitting the vuex store, so follow that data.
<Tree class="tasktree" :value="treeData" edgeScroll
@drop="writeTree" v-slot="{index,node,path,tree}">
If we print the store inside computed.treeData()
computed: {
treeData() {
console.log(this.$store.state)
console.log(this.$store.state.taskTree)
return this.$store.state.taskTree
}
}
It will print :
There you have it, the store now has two submodules, use this.$store.state.tasks !!, not just state.
Unhandled error during execution of beforeCreate hook
Nothing yet.. .see if it happens again.