Open alyhxn opened 7 months ago
2024.04.04
30min
1h20min
10min
10min
@output
:package: task_messenger_v0.0.1Possible next steps:
feedback 2024.04.04
good job :-)
i think all these tasks you mention are great, but i would start with the "addition of chat log" and "communication between users" and then "CRUD for task" :-)
The communication probably needs a link to be copy/pasted for other users to join. I would say clicking a task should display that link in the or task room title bar or something like that.
The level or depths of task tree can be infinite. As deep as a user likes.
Important task is that a single "task" in the tree can have multiple parents. There are examples of that sketched in the old issue 56 https://github.com/wizardamigos/wizardamigos.github.io/issues/56
For example towards the end of this feedback comment https://github.com/wizardamigos/wizardamigos.github.io/issues/56#issuecomment-1193397302
and again here https://github.com/wizardamigos/wizardamigos.github.io/issues/56#issuecomment-1207523567
I do think we will need to go through these old worklogs and feedback comments a lot.
Please try to read through it over time top to bottom, as it will likely answer many questions about many details and then we can still discuss :-)
Finally, i do think, the button "create task" already falls under CRUD and every time possible, let's not do overlay form, but make make the title in the file explorer editable and/or add a new one at the right indentation level (if it is a sub task) and let's write it out there. That is literally also what "vscode" does :-)
One thing though - it HAS to work on mobile, hence "context menu" (right click) is problematic and we need to find alternative techniques for it for all interaction.
2024.04.05
45min
20min
20min
1h
30min
10min
5min
10min
@output
:package: task_messenger_v0.0.2Things I forgot to say in the worklog
Possible next steps:
feedback 2024.04.05
Looks good. It's a bit buggy for me, but i see the progress.
maybe we can try to use 4 letter words for actions, e.g.
create
-> make
delete
-> drop
rename
-> edit
open
-> join
(open is 4 letters, but confused me)I personally would prefer action buttons and task tree below the chat window (basically next to the input window.
In fact - the task tree could collapse to the currently selected task and when clicked, expands like a dropdown/dropup menu to show the whole task tree.
The action buttons are also on the bottom next to the input field and change or adapt based on the selected task.
it would help to have a "focus color" and use it as border color or background color or font color and it should be used to always highlight what is selected and where the focus is. For example, i can't clearly see which task the current chat window belongs to for example.
the open
button seems to connect, but maybe we can call it "connect" instead of open? I assume it means to connect to an existing channel somebody else created.
clicking the +
or -
in front of the task (it could use emojis (➕
and ➖
) should expand/collapse, but clicking the name should select and maybe even allow renaming the task? also - it would be cool to use the exact same ascii characters from the examples below to structure the task explorer.
Regarding multiple parents, this is already drawn in the comments i linked. I will link them here again, but you have to read them to the end and see the emoji-asci drawings.
Have you checked those specific linked feedback comments from my last feedback? Here they are again - especially towards the end of each long feedback comment
Here a snippet from the first linked comment:
📌📭┬🔳roadmap🔗
├📭┬🔳UI/UX design🔗
│ ├📭┬📤┬🔳design button🔗
│ │ │ └➖┬❓button-repo/
│ │ │ ├🖇️🔳implement searchbar🔗
│ │ │ └🖇️🔳implement button🔗
│ │ ├📤┬🔳make button icon🔗
│ │ │ └➖┬❓button-icon.svg
│ │ │ ├🖇️🔳implement searchbar🔗
│ │ │ └🖇️🔳implement button🔗
│ │ └📤┬🔳wireframe button🔗
│ │ └➕─❓button.fig
│ └📪─📤🔳design searchbar🔗
│
└📭┬🔳implementation🔗
│ ┌📥❓button-repo/🖇🔳design button🔗
│ ├📥❓button-repo/button-icon.svg🖇🔳make button icon🔗
│ ├📥❓button-repo/button.fig🖇🔳wireframe button🔗
├📭┬📤┼📥️🔳implement button🔗
│ │ ├➕─📦button-repo/button.js🔗
│ │ ├➕─❓button-repo/button.css
│ │ └➖┬❓button-repo/button.html
│ │ └🖇️🔳demonstrate button preview🔗
│ └🔳write button js, css and html
└📭─📤─📥️🔳implement searchbar🔗
The above shows "inputs" and "outputs"
├📭┬📤┼📥️🔳implement button🔗
│ │ ├➕─📦button-repo/button.js🔗
│ │ ├➕─❓button-repo/button.css
│ │ └➖┬❓button-repo/button.html
│ │ └🖇️🔳demonstrate button preview🔗
│ ┌📥❓button-repo/🖇🔳design button🔗
│ ├📥❓button-repo/button-icon.svg🖇🔳make button icon🔗
│ ├📥❓button-repo/button.fig🖇🔳wireframe button🔗
├📭┬📤┼📥️🔳implement button🔗
In summary, see next:
┌📥❓button-repo/🖇🔳design button🔗
├📥❓button-repo/button-icon.svg🖇🔳make button icon🔗
├📥❓button-repo/button.fig🖇🔳wireframe button🔗
📌📭┬📤┼📥️🔳implement button🔗
│ ├➕─📦button-repo/button.js🔗
│ ├➕─❓button-repo/button.css
│ └➖┬❓button-repo/button.html
│ └🖇️🔳demonstrate button preview🔗
└🔳write button js, css and html
Above you can see the inputs have an e.g. 🖇🔳design button🔗
at the end, which indicates where the input came from. The outputs have a plus, e.g. ├➕─❓button-repo/button.css
, so you can expand and see the next tasks that output is used as an input, e.g.
│ └➖┬❓button-repo/button.html
│ └🖇️🔳demonstrate button preview🔗
The same we have in the second comment for tasks. ... below follows a more detailed example
┌📥❓button-icon.svg🖇🔳make button icon🔗
├📥❓button.fig🖇🔳wireframe button🔗
┌📭┬📤┼📥️🔳conceptualize button🔗
│ │ ├➕─📦button-repo/button.js🔗
│ │ └➕─❓button-repo/button.css
| ┌📪─🔳roadmapping🔗👑👷david
├📭┼🔳UI/UX design🔗👑bob👷david
| ├📭─📤─🔳implement searchbar🔗👑charly❔
| └📭─📤─🔳implement button🔗👑
│ ┌👥eve🔗
│ ├👥ralf🔗
│ ├❓button-sketch.jpg🖇🔳make button sketch🔗
📌📪┼📤┼🔳design button🔗👑david👥
│ └➖┬❓button-repo/
│ ├📭─📤─🔳implement searchbar🔗👑charly❔
│ └📭─📤─🔳implement button🔗👑
│
├📭─📤─🔳implement menubar🔗👑charly❔
└📭─📤─🔳implement overlay dialog🔗👑
Here above you can see the design button
task is "pinned" ...the idea is if you have a very large list of tasks, you can pin some, but regardless of pinning at any point, just like the task: 📌📪┴📤┼🔳design button🔗👑david👥
....
button-sketch.jpg
from make button sketch
button-repo/
implement searchbar
implement button
implement menubar
implement overlay dialog
conceptualize button
UI/UX design
In the above picture, the refs
are misleadingly used.
I get that pass_through
is supposed to mean forward
message or potentially it we could say to keep it 4 letters, that this kind of message type could be just called send
(basically as a request to the receiver to send to somebody a message.
Now that message content might be delivered in the data:
section to describe what and where to send things, thus, e.g.:
data: { to: users, type:
on_create_task, data: { value: input.value, id: task_id } }
So instead of refs
it is all packed into the body, which describes he exact details of the message with type "send"
:-)
Oh and i guess a from: opts.username
is missing???
We are currently not yet using refs.
Refs are only supposed to be used for one use case, which is to have "named pointers" to other message.head
s.
For example, to indicate a message is a reply/response/reaction to a previous message with the following refs: { cause: previous_message.head }
...where head: [by, to, mid]
has that structure of sender, receiver and message id as an array.
BASICALLY: Let's just think of the message.data
of a message.type === 'send'
message as another message that is shuttled to the destination, thus, it should look like:
const id = opts.username
users.forEach(user => {
const message = {
head: [id, user.id, user.mid++],
refs: {},
type: 'on_create_task',
data: { value: input.value, id: task_id }
}
const shuttle_message = {
head: [id, channel_up.send.id, channel_up.mid++],
refs: {},
type: 'send',
data: message,
}
channel_up.send(shuttle_message)
})
The above has a similar issue, basically the "refs" content should be used in data, thus:
const id = opts.username
users.forEach(user => {
const message = {
head: [id, user.id, user.mid++],
refs: {},
type: 'on_post_msg',
data: { value: content, id: chat_id }
}
const shuttle_message = {
head: [id, channel_up.send.id, channel_up.mid++],
refs: {},
type: 'send',
data: message,
}
channel_up.send(shuttle_message)
})
Basically, it is important to know the destination address, which i supposed should be knowable, by clicking on the messenger interface of "bob's" messenger, to copy/paste bob's address and maybe combined with a task id to the clipboard and then going to "ana's" messenger interface and clicking e.g. "join" and then paste the task id and/or bob's address ...and in the input event handler from clicking join, we would use that data to send a message from bob to ana and also from ana back to bob and so forth.
We can store ana's address (maybe the clipboard would even contain ana's nickname to store it as an state.aka[nickname]
or whatever and we initialize it with .mid = 0
...so the first message will use that when we send a message and write .mid++
into the message that we store in the shuttle_message.data
:-)
Now when the intermediary (e.g. the parent component) receives such a message of type: "send"
, it can send a message in the direction of the recipient and set refs: { cause: message.head }
which means the message that will be received by the next stop can repeat the same process and finally, every step checks the message.data section if the message.data.head[1]
is their id, if so, they are the destination and they do not have to forward the message anymore.
The intermediate receiver also checks for e.g. message.refs.origin
and if that is undefined, they know they are the first "intermediate receiver", so they should also set next_message.refs.origin = message.head
.
Every next intermediate receiver before the final destination just copies over message.refs.origin
, so the final destination can see who was the original sender and was the head of the original message.
**This allows the final receiver to reply with a message back and set the
// FINAL RECEIVER:
node.on(message => { // received by last inermediate sender
// ...
const reply_message = { ... }
replay_message.type = 'send'
// ...
reply_message.data.refs = {
cause: message.head, // last intermediate sender
}
channel_up.send(reply_message)
})
Now the first "intermediate receiver" for the "reply message", will again see there is not message.refs.origin
yet, so they set
next_message.refs.head = message.head
next_message.refs.origin = message.head
... then everything continues just the same way, until the original sender receives the message and checks that they are the final destination.
They will check the message.origin
and need to lookup if they have sent a message to that origin (=sender) in the past and if that is the case (which it is), they will process the response.
IMPORTANT NOTE: The message.refs.origin
always uniquely defines a specific message, so a receiver can know exactly what that original message was and treat a reply message as a response to it
Your question
Q: how does bob know ana created a new task?
A: Bob does NOT know. The tasks are NOT SYNCED :-)
Everyone has their own unique set of tasks, only some tasks are synced - maybe the UI should indicate if a task is a shared task (we could use: 👤(2)
) behind a task name?
Only "some" tasks are synced, based on what bob and ana share "out of band", which means, e.g. by ana clicking on her messenger to copy/paste an invite to a task and then e.g. by bob pasting that invite and joining that specific task.
Now if task1
is the invited task, then when bob and ana both joined, they are both supposed to see the sub tasks and when bob clicks one of those sub tasks, they can join those as well and see even more sub tasks ... it get's synchronized on request.
Also, there should be a way to QUIT a task again, but it isn't deleted, because bob can still re-join the task with a new invite.
Your proposal tasks sound good. let's do them, but let's also take extra care for having the things you already implenmented "bug free" :-)
1h
35min
25min
1h
7min
13min
@output
:package: task_messenger_v0.0.3feedback 2024.04.13
The feedback for this worklog is part of this comment: https://github.com/serapath/task-messenger/issues/4#issuecomment-2053739842
2024.05.02
1h20min
20min
30min
30min
1h
10min
20min
@output
:package: task_messenger_tree_v0.0.4@output
:package: task_messenger_list_v0.0.4feedback 2024.05.05
(1/2)
First the refactoring feedback.
+1 for generating a separate file for each peer (e.g. data_bob.json, data_ana.json)
todo:
these files should later be generated from the DB
module instances peers use. The DB
module stores in localStorage and if we clear localStorage, we can import the data from an exported json file to restore it.
{
rooms: {
'': [{ head: '', type: '', data: 'hello', meta: { date: 12315262345235 }}]
'bob': [{ head: '', type: '', data: 'hi', meta: { date: 12315262345289 }}]
}
}
todo:
it should be called message.meta.date
not "data". This was my mistake in the old feedback. sorry :-)
todo:
great that it sorts by date, but it should also respect message.refs.cause
. A reply to m0 "hello" might say "hi" in m1 and have m1.refs.cause pointing to m0.head
old feedback:
message.refs[name] = head
It might be good to be able to e.g. "highlight" other messages in the log, if they were contained by a message via "message.refs" heads. Think of normal messenger when you "reply" to a message. Or maybe it just highlights previous messages when you click a specific message Or maybe you can press a button to "collapse" all message which are not in the "message.refs" chain of a particular message (directly or indirectly). SORTING: based on topological sorting + date based + red markers when date + topological dont agree
old feedback:
TASKS[273].room = { '': [m0], [ana_ID]: [] }
m0 is message0 when bob creates task 273 and contains infos e.g. m0.data contains the arguments passed to creating task 273 initially
this seems to be missing. When a fresh task is created, it should have at least one message in the chat log of the person who created the task, which is a system message with the parameter arguments which were used when creating the task.
todo:
add missing first message when creating a room
thank you for explaining.
my feedback on that would be what i did with "render" message function
-> there were 2 different functions which had the same code
--> so i copied that same code into render function and replaced
the code in those 2 different function with a call to render instead
In the screenshot you see line 163-166 of add_node_sub
is almost identically with line 137-140 of add_node_root
const space = ''
const grand_last = last ? 'a' : ''
const prefix = last ? '' : ''
const opts = { space, prefix, grand_last }
const element = html_template(opts) // for example
The idea is to make a function, e.g. html_template
where everything that is the same goes inside that function and everything that is different goes inside of the parameters which are passed to the function
Anyway, one thing that would be good if we at least turn event handler into functions:
// e.g.
inp.onclick = () => {
if(inp_open){
inp.innerHTML = '🗃'
out_open ? out.innerHTML =
//...
}
}
// becomes
inp.onclick = inp_onclick
return
function inp_onclick (event) {
if (inp_open) {
inp.innerHTML = '🗃'
out_open ? out.innerHTML =
// ...
}
}
// that way reading becomes a bit easier
The opts
variable is also still the same as it was, even though it was mentioned in the feedback.
@alyhxn could you at the end of your work and before recording the next worklog always double check the last feedback to see if anything is missing or was forgotten? that would be sweet :-)
feedback 2024.05.05
(2/2)
I watched the tree
vs list
architecture as well.
I understand the differences.
The issue is, that based on this we would pick the tree
architecture for sure, but the thing is having not just many nodes (e.g. 100 tasks each with 100 sub tasks, each with 10 subtasks, etc... let's say 4 levels deep.)
That's 1000 100 10 * 10 = 10_000_000 tasks
On my computer, a loop with so many tasks
{
var t0 = performance.now()
var x = 0
for (var i = 10_000_000; i--;) {
x += i
}
console.log(x)
var t1 = performance.now()
console.log(t1 - t0)
}
Takes ~300ms to run.
So we can increase some task levels to make it take 2-3 seconds or even 30 seconds.
And then we can benchmark our task messenger structure to see that completly removing and adding tasks nodes to the DOM keeps constant performance, regardless of the amount of tasks. And it also keeps constant memory footprint.
These things can also be inspected in the developer tools and i can share some resources how that is being done.
list
vs tree
When it comes to removing nodes from the dom and adding them back in while lazy loading them on scrolling, the architecture might become more relevant and it might be more easy with a list - so comparing that and also measuring the real performance difference should be our indicator for choosing architecture :-)
In order to perfectly support loading and unloading requires task infos from the database based on scroll position, we need to optimize our infrastructure IO
and DB
, because those might need to be restored as well and performance will only be smooth if IO
and DB
are optimized for these requirements, so this will take some little "detour" before we can get back into the task messenger and continue the actually "task explorer" and "task messenge" work, but it will pay off in the long run and we are here for highest quality standards and the long run, so no need to rush it, but rather to be really really thorough to get the "best in class" quality :-)
2024.05.07
1h15min
30min
15min
5min
15min
@output
:package: task_messenger_v0.0.5feedback 2024.05.07
Thanks. Looks like a good worklog. Here some additional feedback:
it would be good if all the tasks you spot that are for "some time later" would be added as todos in the top level comment of the issue, so we wont forget them :slight_smile:
that way, the top level issue can slowly collect tasks and sub tasks to represent our future plans and roadmap for where we wanna get to :slight_smile:
e.g. a task to remind us of: data_bob.json, data_ana.json, etc... should be exported directly from DB module and later imported into DB module as well
Basically, when processing feedback, ...either it should be included into the work for the next worklog, or if it cant be done right away, it should be added as a todo for later so we will for sure not forget it
e.g. same for the "reply" feature ...if it cant be done immediately, at least it should be added as a task to the top level comment.
if that feature depends on some other task, that should be indicated by using the output of that other task as input to the "reply" feature task ...same goes for exporting data from DB module.
that requires having a DB module first, so the DB module as output should be an input to that export/import task for the future :slight_smile:
Regarding message format, it has a very specific and very strict format, which looks like this:
on(message => {
const by = `<address of sender>`
const to = `<address of receiver>`
const mid = `<message ID counter>`
// `mid` indicates how many messages have been sent from "by" to "to".
// -> if there was a DB book append only log to store the sent messages from "by" to "to", then `mid` would be `.length` of that append only log
const head = [by, to, mid]
const refs = {}
const type = 'text'
const data = 'Hello back'
const meta = { date: Date.now() }
const msg = {
head,
refs,
type,
data,
meta,
}
// `msg.refs` is an object
// every key, e.g. `msg.refs.cause` value is a `head` of another message
msg.refs.cause = message.head
console.log(msg)
book.add(msg)
const {
send
} = state.net[message.head[0]]
send(msg)
})
every message has exactly that structure and not any different structure.
we should probably write a function to verify that structure.
I do think this is also supposed to be true for chatroom
array.
Ideally, the chatroom would only consist of an ordered list of head
s and then when rendering, it would look up the actual message content and other data in based on those head
s :slight_smile:
That way we dont have to duplicate data for now and keep things more systematic.
Things is also, the chatroom.sort
in the end is only based on "date" and not yet on any dependencies expressed through message.refs
...
maybe you missed one tiny old feedback, the old feedback about the json data structure and you jumped directly to the "first message" in the room.
But it also shows the key
should not be the "nickname" of a peer (e.g. "ana") but it should be the peer's address
TASKS[273].room = { '': [m0], [ana_ID]: [] }
the ana_ID
is not "ana"
otherwise, thanks for the worklog. looks good.
Agree with not touching the list architecture branch until we completed the other refactoring parts :slight_smile:
2024-05-08
5min
20min
1h10min
15min
5min
@output
:package: task_messenger_v0.0.6There was not much to explain. Just I wanted to say that these updates may become useless when those new modules are implemented.
todo
@input
:package: serapath_discord_msg@output
:package: task_messenger_v0.0.1 from comment@input
:package: task_messenger_v0.0.1 from comment@input
:package: david_mobile_v0.0.4@output
:package: task_messenger_v0.0.2 from comment[ ] Update task_messenger_v0.0.2
@input
:package: task_explorer_v0.0.1 from comment@input
:package: task_messenger_v0.0.2 from comment@output
:package: task_messenger_v0.0.3 from comment[ ] Update task_messenger_v0.0.3
@input
:package: task_messenger_v0.0.3 from comment@output
:package: task_messenger_v0.0.4 from comment[ ] Update task_messenger_v0.0.4
@input
:package: task_messenger_v0.0.4 from comment@output
:package: task_messenger_v0.0.5 from comment[ ] Update task_messenger_v0.0.5
@input
:package: task_messenger_v0.0.5 from comment@output
:package: task_messenger_v0.0.6 from commentDB
Module@input
:package: [DB_v0.0.?]@input
:package: [IO_v0.0.?]