MMOframework
Pourquoi l'IA Playground Bibliothèques Documentation Rechercher Agence
FR EN
Index

mmo-kanban

1 symbole · générée le 27 Oct 2026

element

mmo-kanban

mmo-kanban.jhs:1

A project board in the manner of GitHub Projects: tickets seen as a board, as a tree-shaped list or as a timeline (a Gantt chart drawing the constraints between tickets).

<mmo-kanban mode="board" group="status" zoom="week" readonly lenient busy></mmo-kanban>
Étend
CustomShadowElement
The board's columns are only a way of looking at the tickets: they are made from the tickets' `status`, their `labels` or their `category`, whichever the board is grouped by, and dropping a card in a column gives it that column's status, label or category. The statuses, the labels and the categories are the board's own, edited in its settings (or in the data). A ticket can hold sub-tickets (`parent`), and a constraint: a tree of conditions, combined with AND, OR and NOT, that the board enforces when a ticket changes. Its data is a plain object, read and written through the `data` property or given inline as a `<script type="application/json">` child: { "statuses": [{"id": "todo", "label": "Todo", "type": "backlog", "limit": null}, ...], "labels": [{"id": "release", "label": "release"}, ...], "categories": [{"id": "web", "label": "Website", "color": "purple", "icon": "globe"}, ...], "people": [{"id": "marc", "label": "Marc Mouret", "avatar": "https://..."}, ...], "tickets": [{"id": "3", "title": "Ship", "status": "todo", "labels": ["release"], "category": "web", "parent": "1", "start": "2026-10-05", "end": "2026-10-09", "assignee": "marc", "description": "", "constraint": {"type": "depends", "ticket": "2"}}, ...] } A ticket may carry fields the board does not draw, which it keeps as they are: `pages`, the pages it is about (`[{"route": "settings/users", "target": "#save"}]`: mmo.admin's developer layer shows the ticket on them), who reported it (`reportedBy`), what was captured when it was (`context`). A status, a label or a category may have a `color` (gray, blue, teal, green, yellow, orange, red, pink, purple, or a `#rrggbb`) and an `icon` (an `<mmo-icon>` name), set in the board's settings; without them a status takes its type's, a label or a category one of the colours by its name. `people` are who a ticket can be assigned to (anyone else typed in is welcome too). The statuses default to backlog, todo, in progress, review / testing and done. A status's `type` is what a ticket with it is: `backlog` (not started), `active` (started) or `done`; giving a ticket a status stamps `startedAt` / `doneAt`, which is what the constraints are checked against. A label a ticket uses and the board does not know is added to the board's labels. The conditions of a constraint, for the ticket B that holds it: - `{"type": "depends", "ticket": "A"}` B depends on A: B cannot start before A is done. - `{"type": "after", "ticket": "A"}` B must be done after A: B cannot be done before A is. - `{"type": "before", "ticket": "A"}` B must be done before A: A cannot be done before B is. - `{"type": "partOf", "ticket": "A"}` B is part of A: A cannot be done before B, and B lies within A on the timeline. A sub-ticket is part of its parent without saying it. - `{"type": "start", "op": "before|at|after", "date": "2026-10-05"}` B must start before / on / after that date, and `{"type": "end", ...}` the same for when B is done. - `{"type": "and", "items": [...]}`, `{"type": "or", "items": [...]}`, `{"type": "not", "item": {...}}`. Each condition is true, false or still open (A is not done yet), and AND / OR / NOT combine the three as a three-valued logic does. A move that makes a constraint false — any ticket's, not only the one moved — is refused and the reason shown, unless the board is `lenient`, which only warns. On the timeline, the same conditions are checked against the planned dates instead, and drawn: an arrow per condition on a ticket, a flag per condition on a date, red where the plan breaks it. A ticket's discussion is shown in its editor once the page gives the board a `discussion`: an object whose functions reach wherever the comments are, each returning a promise (`load` is required, the others let the viewer write; a `readonly` board only reads): board.discussion = { load: (ticket) => ..., // its comments, or null when the ticket has no discussion add: (ticket, body, parent) => ..., // the new comment; `parent` the id of the one it answers, or null update: (ticket, comment, body) => ..., // the comment as it is now remove: (ticket, comment) => ... }; On the server, `MMO\client\controllers\KanbanController` serves a board (`kanban/{board}.json`, and its tickets' discussions) from any repository of `KanbanBoard`, `KanbanTicket` and `KanbanComment` entities, and commits the board's changes to it: a JSON file, a database, GitHub (mmo.git's `GitHubRepository`). A comment is `{id, parent, author: {login, name, avatar, url}, role, body, createdAt, updatedAt, url, mine}`: `body` is markdown (written in `<mmo-markdown-editor>` when the page has it, its html never live), `parent` the comment it answers, `mine` whether the viewer may change it. They are shown in threads, a reply under what it answers, or by date, oldest or newest first: the order the viewer last picked. A ticket's `comments` is how many it has, shown on its card. A description's fenced blocks whose language is an AI agent's name (`AGENTS`) are prompts for that agent: ```` ```claude ````, ```` ```chatgpt ````, ```` ```gemini ````..., ```` ```ai ```` for any. Its card shows which agents it has prompts for, and the search finds them (`ai:` the tickets with a prompt, `ai:claude` with a claude one). On the server, `MMO\client\classes\KanbanPrompts` reads them the same way: the kanban controllers' `prompts.json` hands an agent the tickets meant for it.

Index

modewhat is shown: board (default), list or timeline
groupwhat the board's columns are made from: status (default), label or category
zoomthe timeline's scale: day, week (default) or month
readonlynothing can be moved or edited
lenienta move that breaks a constraint is made anyway, with a warning, instead of refused
busythe board waits on its data, or on a save: a spinner says so, with the attribute's text if it has one (busy="Saving…").
MODES static
SCALES staticpixels per day, by zoom
ROW staticthe timeline's geometry: header, row and bar heights
HEAD static
BAR static
GROUPS static
STATUSES static
AGENTS staticthe languages of a description's fenced block that make it an AI prompt: an agent's name, ai for any
COLORS staticthe colours a status, a label or a category can take: the theme's, so they follow it into the dark
ICONS staticthe icons the settings offer
TYPE_LOOKS statica status's look by its type, until it has its own
EDITOR_WIDTH staticthe width a ticket's panel asks the application for, in pixels: the user's own wins
EDITOR_COMPACT staticbelow this width an editor is one column, its properties above the rest
THREAD_DEPTH statica reply deeper than this is shown at this depth, saying whom it answers
TYPES static readonly accessorwhat a status's type is called, in the viewer's language
CONDITIONS static readonly accessorthe conditions, by type: what the editor calls them (in the viewer's language) and what kind of value they take
OPS static readonly accessorthe operators of a condition on a date, and what the editor calls them
ViewDefault static readonly accessor
mode accessorWhat is shown: board, list or timeline.
group accessorWhat the board's columns are made from: status, label or category.
zoom accessorThe timeline's scale: day, week or month.
readonly accessorWhether nothing can be moved or edited.
lenient accessorWhether a move breaking a constraint is made anyway (with a warning).
busy accessorWhether the board waits on its data, or on a save: true, or what it waits on ('Saving to GitHub…').
data accessorThe board's data: a copy of its statuses, labels, categories and tickets.
discussion accessorWhere the tickets' discussions are: {load, add, update, remove} (the class's documentation), or null for none.
TICKET_FIELDS static readonly accessorthe fields of a ticket the board draws and edits; any other is kept as it is (normalizeTicket)
ORDERS static readonly accessorthe orders a discussion is shown in
prompts(text) staticThe AI prompts of a ticket's description: as MMO.core.markdown reads a fence, and KanbanPrompts::Extract on the server -- a block nested in another fence is text.
constructor()
init()
isSaving(id)Whether a ticket waits on a save: it cannot be changed until it is over (busy).
refuseSaving(id)refuse a change of a ticket being saved, saying so: true when refused
drawLocks()show which tickets are being saved: their cards, rows and bars, and their editors (busy)
drawBusy()show, or hide, what says the board is busy (busy)
load(data)Replace the board's data.
configure(lists)Set the board's statuses, labels and categories, from lists of objects or of names.
lookOf(item)
learnLabels(tickets)the labels used by tickets and not known yet join the board's
isOn(value)
printf(text, data)A translated text with its {placeholders} filled.
statusLabel(status)What a status is called on screen: a default one (STATUSES) not renamed speaks the viewer's language, while the label the board saves stays as it is.
normalizeTicket(t)
normalizeConstraint(node)Make a condition tree the board can use: an array is an AND, an unknown type is dropped.
index()rebuild the lookups after a change of this.tickets
childrenOf(tickets)
nextId()
isAncestor(ancestor, id)Whether a ticket is an ancestor of another (or the same).
statusType(id)
defaultStatus()the status of a new ticket: the first that is not the backlog, when there is one before work starts
toDay(value)────────────────────────────────────────────── Dates: days are 'YYYY-MM-DD' strings, events are local 'YYYY-MM-DDTHH:MM:SS' stamps ──────────────────────────────────────────────
localDay(date)
now()
dayNumber(day)
dayString(n)
formatDay(day)
compareTime(a, b)Compare two times at the precision of the less precise: a day against a stamp compares the days.
world(tickets, now)The world a constraint is checked in: tickets, their lookups and the time.
isDone(t)
isStarted(t)
evaluate(node, b, world, mode)Evaluate a condition tree for a ticket.
stateTicket(type, a, b)a condition on another ticket, against what happened
planTicket(type, a, b)a condition on another ticket, against the planned dates
stateDate(node, b, world)a condition on a date, against what happened: an event not yet happened may still keep it
planDate(node, b)a condition on a date, against the planned dates
fullConstraint(t, world)A ticket's whole constraint: its own, and being part of its parent.
violations(tickets, now)The tickets whose constraint is broken.
attempt(mutate)Try a change on a copy of the tickets: what it would break.
commit(mutate, moved)Make a change, unless it breaks a constraint (and the board is not lenient).
whyBlocked(t)Why a ticket cannot go to its next step (start, or be done), if it cannot.
describe(node, world, nested)Describe a condition tree in words.
failing(node, b, world, mode)Describe what makes a condition tree false: the items of an AND that are, the rest whole.
shorten(text, length)
leaves(node, negated, alternative, found)The conditions of a tree that name another ticket or a date, with how they are reached.
prune(node, id)Remove the conditions naming a ticket.
setStatus(t, status, now)Give a ticket a status, stamping when it started and was done.
moveTicket(id, group, to, beforeId, from)Drop a ticket in a column of the board: give it that column's status, label or category, and put it before another ticket.
addTicket(ticket)Add a ticket.
updateTicket(id, changes)Change a ticket's fields (a new status stamps it as a move does).
removeTicket(id)Remove a ticket: its sub-tickets go to its parent, and the conditions naming it go.
schedule()refresh once, after whatever else changes now
refresh()
matchesFilter(t)whether a ticket matches the filter
refBadge(t)What a ticket is called elsewhere (its ref: gh#255 for a GitHub issue, which mmo.git's BoardSync writes), a link to its page (url) when it has one.
look(kind, item)How a status, a label or a category looks: its own colour and icon, or its kind's.
labelItem(id)
badge(kind, item, text)A status, a label or a category as a pill, in its colour, with its icon.
person(person, css)Someone, as a picture (or initials) and a name.
assignable()
icon(name, css, title)
stateIcon(t)the state of a ticket, as an icon: broken, blocked, done
columnsFor(group)The board's columns for a grouping: one per status, label or category — and, for labels and categories, one first for the tickets that have none.
renderBoard(world)
mark(col)what stands for a column before its name: its icon, in its colour, or a dot
scrollToColumn(id)bring a column of the board into sight
markVisibleColumn()the strip of columns says which one is in sight
scrollStrip(chip)the strip scrolled to a chip, and nothing else: scrollIntoView scrolls every scrolling ancestor too -- the page of a board low on it (mmo.admin's checklists) jumped to it as it loaded
card(t, world, col)
onCardKey(event, t, col)Enter opens a card; Alt+arrows move it across columns and within its column
placePlaceholder(cards, clientY)the gap a dragged card shows where it would land, in a column at a height of the screen
placeholderNext()the ticket the dragged card goes before: the card after the gap, null for the end
clearDropMarks()
wireDrop(cards, group, col)a column's cards take the dragged one, at the place the pointer shows
wireTouchDrag(card, t, col)Drag a card with a finger: a long press picks it up (a quick swipe still scrolls), it follows the finger, the board scrolls when it nears an edge, and it drops in the column under it — or on a colu…
startTouchDrag(card, t, col, start)
moveTouchDrag(drag)
endTouchDrag(drag, cancelled)
scrollParent()the box the page scrolls in, through the shadow roots and slots this element sits in
quickAddFooter(col)
rows(world)The tickets in tree order, as rows: the filtered ones and their ancestors, below an unfolded parent.
toggle(id)
toggleButton(row)
renderList(world)
renderTimeline(world)
route(from, to, kind)The path of an arrow between two bars, in right angles.
wireBars(svg, bars, px)a bar is moved by its body and resized by its ends, a day at a time
edit(id, defaults)Open a ticket, or a new one, in the side panel of the application (<mmo-app>): a tab per ticket, the same ticket twice shows its tab again.
usesPanels()whether tickets open in the application's side panel (its tabbed one) rather than in a dialog
panelKey(id)a panel's key: the same ticket of the same board is one panel
editorTitle(editor)
refreshEditors()Draw the open editors again after a change of the board: the ones with changes not saved are left as they are, the ones whose ticket is gone close.
lockEditor(editor)An editor whose ticket is being saved waits for it: its fields cannot be reached, and it says why (busy).
closeEditor(editor)close an editor: its panel, or the dialog
renderEditor(editor)Draw an editor: its tabs (the ticket, its discussion), and the ticket's form -- its text on the left, its properties on the right, picked from dropdowns.
drawTabs(editor)The tabs of an editor -- the ticket, its discussion -- drawn again when the count of comments changes; only an existing ticket with a discussion has them.
isCompact(editor)whether an editor is too narrow for two columns
watchEditorWidth(editor)an editor goes to one column, and back, as its panel or its dialog is resized
dropdown(box, button, pop, onOpen)A popover that opens under its button, and closes on Escape or on a click anywhere else.
picker(spec)A dropdown to pick a value, or several: a button showing what is picked, and a list to pick from, filtered by what is typed in it.
lookPicker(kind, item)The colour and the icon of a status, a label or a category, in the board's settings: a button showing them, and a popover to pick them.
descriptionEditor(t, ro, bind)The description of a ticket: markdown, in <mmo-markdown-editor> (a plain textarea when the page does not have it).
addTriggers(editor, id, people)# suggests the board's tickets, @ the people: the ones tickets are assigned to, and more.
discussionSection(editor)Start the discussion of an editor's ticket: its state lives in editor.talk, its section is drawn by
canComment()whether the viewer may write in the discussions
loadDiscussion(editor) async(Re)load the comments of an editor's ticket.
normalizeComment(c)
countComments(editor)the card says how many comments its ticket has
drawDiscussion(editor)Draw an editor's discussion: its header (the count, the order, reload), its comments, and the editor of a new one.
commentList(editor)The comments, in the viewer's order: by date, or in threads -- a reply under what it answers, a reply to a comment that is gone starting a thread of its own.
commentNode(editor, c, byId, sayParent)A comment: who wrote it and when, what it says, and what the viewer can do with it.
commentEditor(editor, kind, target)The editor of a comment: a new one, a reply, or a change of one's own.
focusComposer(editor, key)put the caret in a comment's editor, once it is drawn
sendComment(editor, kind, target) asyncSend what a comment's editor holds: a new comment, a reply, or a change.
removeComment(editor, c) asyncDelete one's own comment, once asked: its replies stay, answering a deleted comment.
showComment(editor, id)scroll to a comment of the discussion, and make it flash
setDiscussionOrder(order)
storedOrder()
ago(date)
fullDate(date)
initials(name)
conditionEditor(t, node, set, redraw, preview, root)The editor of one condition, and of the ones it holds.
newCondition(t)
convertCondition(t, node, type)a condition turned into another type, keeping what both share
save(t, isNew)Save a ticket being edited.
configureBoard(lists)Change the board's statuses, labels and categories.
editSettings()Open the board's settings: its statuses, labels and categories.
confirmRemove(id, editor) async
notify(title, lines, tone)Say something for a while, under the toolbar.
(default)a <script type="application/json"> holding the board's data

Attributs6

mode

mmo-kanban.jhs

what is shown: board (default), list or timeline

mode="board"

group

mmo-kanban.jhs

what the board's columns are made from: status (default), label or category

group="status"

zoom

mmo-kanban.jhs

the timeline's scale: day, week (default) or month

zoom="week"

lenient

mmo-kanban.jhs

a move that breaks a constraint is made anyway, with a warning, instead of refused

lenient

busy

mmo-kanban.jhs

the board waits on its data, or on a save: a spinner says so, with the attribute's text if it has one (busy="Saving…"). Without a ticket yet, it stands in for the board. The tickets changed since it was last busy are the ones being saved: until it is not, they cannot be moved, edited or deleted, and say so

busy

Constantes14

SCALES

staticmmo-kanban.jhs:157

pixels per day, by zoom

static SCALES = {day: 34, week: 15, month: 4};

ROW

staticmmo-kanban.jhs:160

the timeline's geometry: header, row and bar heights

static ROW = 36;

STATUSES

staticmmo-kanban.jhs:166
static STATUSES = [ {id: 'backlog', label: 'Backlog', type: 'backlog', limit: null}, {id: 'todo', label: 'Todo', type: 'backlog', limit: null}, {id: 'progress', label: 'In progress', type: 'active', limit: null}, {id: 'review', label: 'Review / testing', type: 'active', limit: null}, {id: 'done', label: 'Done', type: 'done', limit: null} ];

AGENTS

staticmmo-kanban.jhs:180

the languages of a description's fenced block that make it an AI prompt: an agent's name, ai for any

static AGENTS = ['claude', 'chatgpt', 'gpt', 'openai', 'codex', 'gemini', 'mistral', 'copilot', 'cursor', 'llama', 'deepseek', 'grok', 'perplexity', 'ai'];

COLORS

staticmmo-kanban.jhs:208

the colours a status, a label or a category can take: the theme's, so they follow it into the dark

static COLORS = { gray: 'var(--mmo-color-text-3)', blue: 'var(--mmo-color-viz-1)', teal: 'var(--mmo-color-viz-2)', green: 'var(--mmo-color-ok)', yellow: 'var(--mmo-color-warn)', orange: 'var(--mmo-color-viz-4)', red: 'var(--mmo-color-bad)', pink: '#D6409F', purple: 'var(--mmo-color-viz-3)' };

ICONS

staticmmo-kanban.jhs:221

the icons the settings offer

static ICONS = [ 'circle', 'circle-dot', 'circle-half-stroke', 'circle-play', 'circle-check', 'circle-xmark', 'circle-stop', 'circle-exclamation', 'status-draft', 'status-pending', 'status-active', 'status-validated', 'status-final', 'status-archive', 'hourglass-half', 'eye', 'magnifying-glass', 'flag-checkered', 'bug', 'star', 'lightbulb', 'screwdriver-wrench', 'code', 'palette', 'book', 'shield-halved', 'lock', 'tag', 'folder', 'bell', 'calendar-days', 'clock', 'users', 'user', 'globe', 'database', 'desktop', 'chart-line', 'flask', 'comments', 'question', 'triangle-exclamation', 'ban', 'ticket', 'bullhorn', 'gear', 'road', 'shapes', 'building', 'handshake' ];

TYPE_LOOKS

staticmmo-kanban.jhs:231

a status's look by its type, until it has its own

static TYPE_LOOKS = { backlog: {color: 'gray', icon: 'circle'}, active: {color: 'blue', icon: 'circle-half-stroke'}, done: {color: 'green', icon: 'circle-check'} };

EDITOR_WIDTH

staticmmo-kanban.jhs:238

the width a ticket's panel asks the application for, in pixels: the user's own wins

static EDITOR_WIDTH = 760;

EDITOR_COMPACT

staticmmo-kanban.jhs:241

below this width an editor is one column, its properties above the rest

static EDITOR_COMPACT = 600;

THREAD_DEPTH

staticmmo-kanban.jhs:2939

a reply deeper than this is shown at this depth, saying whom it answers

static THREAD_DEPTH = 4;

Propriétés14

TYPES

staticreadonlyaccessormmo-kanban.jhs:175

what a status's type is called, in the viewer's language

static get TYPES()

CONDITIONS

staticreadonlyaccessormmo-kanban.jhs:244

the conditions, by type: what the editor calls them (in the viewer's language) and what kind of value they take

static get CONDITIONS()

OPS

staticreadonlyaccessormmo-kanban.jhs:259

the operators of a condition on a date, and what the editor calls them

static get OPS()

mode

accessormmo-kanban.jhs:338

What is shown: board, list or timeline.

get mode() set mode(value)
Type
string

group

accessormmo-kanban.jhs:353

What the board's columns are made from: status, label or category.

get group() set group(value)
Type
string

zoom

accessormmo-kanban.jhs:371

The timeline's scale: day, week or month.

get zoom() set zoom(value)
Type
string

readonly

accessormmo-kanban.jhs:387

Whether nothing can be moved or edited.

get readonly() set readonly(value)
Type
boolean

lenient

accessormmo-kanban.jhs:400

Whether a move breaking a constraint is made anyway (with a warning).

get lenient() set lenient(value)
Type
boolean

busy

accessormmo-kanban.jhs:412

Whether the board waits on its data, or on a save: true, or what it waits on ('Saving to GitHub…').

get busy() set busy(value)
Type
boolean

data

accessormmo-kanban.jhs:482

The board's data: a copy of its statuses, labels, categories and tickets.

get data() set data(value)
Type
object

discussion

accessormmo-kanban.jhs:495

Where the tickets' discussions are: {load, add, update, remove} (the class's documentation), or null for none.

get discussion() set discussion(value)
Type
?object

TICKET_FIELDS

staticreadonlyaccessormmo-kanban.jhs:628

the fields of a ticket the board draws and edits; any other is kept as it is (normalizeTicket)

static get TICKET_FIELDS()

ORDERS

staticreadonlyaccessormmo-kanban.jhs:2934

the orders a discussion is shown in

static get ORDERS()

Méthodes130

prompts(text)

staticmmo-kanban.jhs:189

The AI prompts of a ticket's description: as MMO.core.markdown reads a fence, and KanbanPrompts::Extract on the server -- a block nested in another fence is text.

static prompts(text)
textstring- markdown
retourneArray<{agent: string, info: string, prompt: string, line: number>} in its order; line from 1
customElements.get('mmo-kanban').prompts('```claude\nFix it\n```'); // [{agent: 'claude', info: '', prompt: 'Fix it', line: 1}]

isSaving(id)

mmo-kanban.jhs:438

Whether a ticket waits on a save: it cannot be changed until it is over (busy).

isSaving(id)
idstring
retourneboolean

refuseSaving(id)

mmo-kanban.jhs:443

refuse a change of a ticket being saved, saying so: true when refused

refuseSaving(id)
id

drawLocks()

mmo-kanban.jhs:450

show which tickets are being saved: their cards, rows and bars, and their editors (busy)

drawLocks()

load(data)

mmo-kanban.jhs:516

Replace the board's data.

load(data)
dataobject- {statuses, labels, categories, tickets}; a list left out keeps the current one
retournevoid

configure(lists)

mmo-kanban.jhs:541

Set the board's statuses, labels and categories, from lists of objects or of names.

configure(lists)
listsobject- {statuses, labels, categories}; a list left out is kept
retournevoid

lookOf(item)

mmo-kanban.jhs:568
lookOf(item)
itemobject- a status, a label or a category, as given
retourneobjectits color and icon, the ones it has

learnLabels(tickets)

mmo-kanban.jhs:576

the labels used by tickets and not known yet join the board's

learnLabels(tickets)
tickets

printf(text, data)

mmo-kanban.jhs:598

A translated text with its {placeholders} filled.

printf(text, data)
textstring- what MMO.i18n.$ gave
dataobject
retournestring

statusLabel(status)

mmo-kanban.jhs:608

What a status is called on screen: a default one (STATUSES) not renamed speaks the viewer's language, while the label the board saves stays as it is.

statusLabel(status)
status?object
retournestring

normalizeConstraint(node)

mmo-kanban.jhs:671

Make a condition tree the board can use: an array is an AND, an unknown type is dropped.

normalizeConstraint(node)
node*
retourne?object

isAncestor(ancestor, id)

mmo-kanban.jhs:719

Whether a ticket is an ancestor of another (or the same).

isAncestor(ancestor, id)
ancestorstring
idstring
retourneboolean

defaultStatus()

mmo-kanban.jhs:734

the status of a new ticket: the first that is not the backlog, when there is one before work starts

defaultStatus()

toDay(value)

mmo-kanban.jhs:742

────────────────────────────────────────────── Dates: days are 'YYYY-MM-DD' strings, events are local 'YYYY-MM-DDTHH:MM:SS' stamps ──────────────────────────────────────────────

toDay(value)
value

compareTime(a, b)

mmo-kanban.jhs:776

Compare two times at the precision of the less precise: a day against a stamp compares the days.

compareTime(a, b)
a
b
retourne?number<0, 0, >0, or null when one is unknown

world(tickets, now)

mmo-kanban.jhs:792

The world a constraint is checked in: tickets, their lookups and the time.

world(tickets, now = this.now())
ticketsobject[]
now = this.now()
retourneobject

evaluate(node, b, world, mode)

mmo-kanban.jhs:814

Evaluate a condition tree for a ticket.

evaluate(node, b, world, mode = 'state')In `state` mode, against what happened (columns and stamps): is it kept, broken, or still open? In `plan` mode, against the planned `start` / `end` dates.
node?object- the condition
bobject- the ticket holding it
worldobject- world
mode = 'state'string- state or plan
retourne?booleantrue, false, or null when it cannot be told (yet)

stateTicket(type, a, b)

mmo-kanban.jhs:853

a condition on another ticket, against what happened

stateTicket(type, a, b)
type
a
b

planTicket(type, a, b)

mmo-kanban.jhs:874

a condition on another ticket, against the planned dates

planTicket(type, a, b)
type
a
b

stateDate(node, b, world)

mmo-kanban.jhs:894

a condition on a date, against what happened: an event not yet happened may still keep it

stateDate(node, b, world)
node
b
world

planDate(node, b)

mmo-kanban.jhs:910

a condition on a date, against the planned dates

planDate(node, b)
node
b

fullConstraint(t, world)

mmo-kanban.jhs:922

A ticket's whole constraint: its own, and being part of its parent.

fullConstraint(t, world)
tobject
worldobject
retourne?object

violations(tickets, now)

mmo-kanban.jhs:935

The tickets whose constraint is broken.

violations(tickets, now)
ticketsobject[]
nowstring
retourneMap<string, string>id => why

attempt(mutate)

mmo-kanban.jhs:952

Try a change on a copy of the tickets: what it would break.

attempt(mutate)
mutatefunction(object[], string):void- changes the copy it is given, at the time it is given
retournenext: object[], broken: string[]}

commit(mutate, moved)

mmo-kanban.jhs:972

Make a change, unless it breaks a constraint (and the board is not lenient).

commit(mutate, moved = [])
mutatefunction(object[], string):void
moved = []string[]- the tickets it moves, which their fields do not say
retourneok: boolean, reasons: string[]}

whyBlocked(t)

mmo-kanban.jhs:1005

Why a ticket cannot go to its next step (start, or be done), if it cannot.

whyBlocked(t)
tobject
retournestring[]the constraints it would break, empty when it can

describe(node, world, nested)

mmo-kanban.jhs:1023

Describe a condition tree in words.

describe(node, world = this.world(this.tickets), nested = false)
node?object
world = this.world(this.tickets)object
nested = falseboolean- whether it sits in another, which a group is parenthesised in
retournestring

failing(node, b, world, mode)

mmo-kanban.jhs:1058

Describe what makes a condition tree false: the items of an AND that are, the rest whole.

failing(node, b, world, mode = 'state')
node
b
world
mode = 'state'
retournestring[]

leaves(node, negated, alternative, found)

mmo-kanban.jhs:1074

The conditions of a tree that name another ticket or a date, with how they are reached.

leaves(node, negated = false, alternative = false, found = [])
node?object
negated = false
alternative = false
found = []
retourneobject[][{node, negated, alternative}]

prune(node, id)

mmo-kanban.jhs:1089

Remove the conditions naming a ticket.

prune(node, id)
node
id
retourne?objectwhat is left of the tree

setStatus(t, status, now)

mmo-kanban.jhs:1115

Give a ticket a status, stamping when it started and was done.

setStatus(t, status, now)
tobject- the ticket, changed in place
statusstring
nowstring

moveTicket(id, group, to, beforeId, from)

mmo-kanban.jhs:1140

Drop a ticket in a column of the board: give it that column's status, label or category, and put it before another ticket.

moveTicket(id, group, to, beforeId = null, from = null)
idstring
groupstring- what the columns are made from: status, label or category
to?string- the column: a status, a label or a category id; null for "no label/category"
beforeId = null?string- the ticket it goes before, null for the end
from = null?string- the label it leaves, for label (a ticket is in a column per label it has)
retourneok: boolean, reasons: string[]}

addTicket(ticket)

mmo-kanban.jhs:1199

Add a ticket.

addTicket(ticket)
ticketobject- its fields; status defaults to the first "not started" one after the backlog
retourneok: boolean, reasons: string[], id: string}

updateTicket(id, changes)

mmo-kanban.jhs:1214

Change a ticket's fields (a new status stamps it as a move does).

updateTicket(id, changes)
idstring
changesobject
retourneok: boolean, reasons: string[]}

removeTicket(id)

mmo-kanban.jhs:1245

Remove a ticket: its sub-tickets go to its parent, and the conditions naming it go.

removeTicket(id)
idstring
retourneok: boolean, reasons: string[]}

refBadge(t)

mmo-kanban.jhs:1324

What a ticket is called elsewhere (its ref: gh#255 for a GitHub issue, which mmo.git's BoardSync writes), a link to its page (url) when it has one.

refBadge(t)
tobject
retourneNode | string'' when it has none

look(kind, item)

mmo-kanban.jhs:1341

How a status, a label or a category looks: its own colour and icon, or its kind's.

look(kind, item)
kindstring- status, label or category
item?object
retournetone: string, icon: ?string} a css colour, and an icon name (a label has none unless given one)

labelItem(id)

mmo-kanban.jhs:1363
labelItem(id)
id
retourneobjecta label of the board, or what stands for one it does not know

badge(kind, item, text)

mmo-kanban.jhs:1374

A status, a label or a category as a pill, in its colour, with its icon.

badge(kind, item, text = null)
kindstring- status, label or category
itemobject
text = null?string- what it says, its label by default
retourneHTMLElement

person(person, css)

mmo-kanban.jhs:1386

Someone, as a picture (or initials) and a name.

person(person, css = '')
personobject- {id, label, avatar}
css = ''string
retourneHTMLElement

assignable()

mmo-kanban.jhs:1396
assignable()
retourneobject[]who a ticket can be assigned to: the board's people, and whoever tickets are assigned to

icon(name, css, title)

mmo-kanban.jhs:1404
icon(name, css = 'xs', title = null)
name
css = 'xs'
title = null

stateIcon(t)

mmo-kanban.jhs:1411

the state of a ticket, as an icon: broken, blocked, done

stateIcon(t)
t

columnsFor(group)

mmo-kanban.jhs:1426

The board's columns for a grouping: one per status, label or category — and, for labels and categories, one first for the tickets that have none.

columnsFor(group)
groupstring- status, label or category
retourneobject[][{key, id, label, css, limit, defaults, has(ticket), tone, icon}]

mark(col)

mmo-kanban.jhs:1511

what stands for a column before its name: its icon, in its colour, or a dot

mark(col)
col

scrollToColumn(id)

mmo-kanban.jhs:1516

bring a column of the board into sight

scrollToColumn(id)
id

markVisibleColumn()

mmo-kanban.jhs:1523

the strip of columns says which one is in sight

markVisibleColumn()

scrollStrip(chip)

mmo-kanban.jhs:1544

the strip scrolled to a chip, and nothing else: scrollIntoView scrolls every scrolling ancestor too -- the page of a board low on it (mmo.admin's checklists) jumped to it as it loaded

scrollStrip(chip)
chip

onCardKey(event, t, col)

mmo-kanban.jhs:1642

Enter opens a card; Alt+arrows move it across columns and within its column

onCardKey(event, t, col)
event
t
col

placePlaceholder(cards, clientY)

mmo-kanban.jhs:1671

the gap a dragged card shows where it would land, in a column at a height of the screen

placePlaceholder(cards, clientY)
cards
clientY

placeholderNext()

mmo-kanban.jhs:1692

the ticket the dragged card goes before: the card after the gap, null for the end

placeholderNext()

wireDrop(cards, group, col)

mmo-kanban.jhs:1705

a column's cards take the dragged one, at the place the pointer shows

wireDrop(cards, group, col)
cards
group
col

wireTouchDrag(card, t, col)

mmo-kanban.jhs:1734

Drag a card with a finger: a long press picks it up (a quick swipe still scrolls), it follows the finger, the board scrolls when it nears an edge, and it drops in the column under it — or on a column's name in the strip above a narrow board.

wireTouchDrag(card, t, col)
card
t
col

startTouchDrag(card, t, col, start)

mmo-kanban.jhs:1776
startTouchDrag(card, t, col, start)
card
t
col
start

scrollParent()

mmo-kanban.jhs:1854

the box the page scrolls in, through the shadow roots and slots this element sits in

scrollParent()

rows(world)

mmo-kanban.jhs:1904

The tickets in tree order, as rows: the filtered ones and their ancestors, below an unfolded parent.

rows(world)
world
retourneobject[][{ticket, depth, hasChildren}]

route(from, to, kind)

mmo-kanban.jhs:2229

The path of an arrow between two bars, in right angles.

route(from, to, kind)
fromnumber[]- [x, y]
tonumber[]- [x, y]
kindstring- fs end to start, ff end to end, ss start to start
retournestring

wireBars(svg, bars, px)

mmo-kanban.jhs:2249

a bar is moved by its body and resized by its ends, a day at a time

wireBars(svg, bars, px)
svg
bars
px

edit(id, defaults)

mmo-kanban.jhs:2320

Open a ticket, or a new one, in the side panel of the application (<mmo-app>): a tab per ticket, the same ticket twice shows its tab again. Outside an application, in a dialog.

edit(id, defaults = {})
id?string- null for a new ticket
defaults = {}object- the fields of a new ticket (status, parent…)
retournevoid

usesPanels()

mmo-kanban.jhs:2361

whether tickets open in the application's side panel (its tabbed one) rather than in a dialog

usesPanels()

panelKey(id)

mmo-kanban.jhs:2366

a panel's key: the same ticket of the same board is one panel

panelKey(id)
id

refreshEditors()

mmo-kanban.jhs:2378

Draw the open editors again after a change of the board: the ones with changes not saved are left as they are, the ones whose ticket is gone close.

refreshEditors()

lockEditor(editor)

mmo-kanban.jhs:2398

An editor whose ticket is being saved waits for it: its fields cannot be reached, and it says why (busy).

lockEditor(editor)Its discussion, saved apart, stays open.
editorobject

closeEditor(editor)

mmo-kanban.jhs:2409

close an editor: its panel, or the dialog

closeEditor(editor)
editor

renderEditor(editor)

mmo-kanban.jhs:2421

Draw an editor: its tabs (the ticket, its discussion), and the ticket's form -- its text on the left, its properties on the right, picked from dropdowns. The form is drawn again on every refresh of the board; the discussion only once (discussionSection), so what is being typed in it stays.

renderEditor(editor)
editorobject
retournevoid

drawTabs(editor)

mmo-kanban.jhs:2625

The tabs of an editor -- the ticket, its discussion -- drawn again when the count of comments changes; only an existing ticket with a discussion has them.

drawTabs(editor)
editorobject
retournevoid

isCompact(editor)

mmo-kanban.jhs:2653

whether an editor is too narrow for two columns

isCompact(editor)
editor

watchEditorWidth(editor)

mmo-kanban.jhs:2659

an editor goes to one column, and back, as its panel or its dialog is resized

watchEditorWidth(editor)
editor

dropdown(box, button, pop, onOpen)

mmo-kanban.jhs:2677

A popover that opens under its button, and closes on Escape or on a click anywhere else.

dropdown(box, button, pop, onOpen)
boxHTMLElement- holds the button and the popover
buttonHTMLElement
popHTMLElement
onOpenfunction():void- fills the popover, each time it opens
retourneopen: function():void, close: function(boolean=):void, isOpen: function():boolean}

picker(spec)

mmo-kanban.jhs:2722

A dropdown to pick a value, or several: a button showing what is picked, and a list to pick from, filtered by what is typed in it.

picker(spec)
specobject- options(): [{value, text, render()}]: text is what the filter searches, render() draws the option - value: what is picked, an array when multiple - multiple: several can be picked; the list stays open - none: what "nothing" is called, when nothing is allowed (single only) - custom: a typed value that is not in the list can be picked, offered as {custom} "value" - placeholder: what the button says when nothing is picked - footer(): something to show under the list - readonly, label (for assistive technologies), onChange(value)
retourneHTMLElement

lookPicker(kind, item)

mmo-kanban.jhs:2834

The colour and the icon of a status, a label or a category, in the board's settings: a button showing them, and a popover to pick them.

lookPicker(kind, item)
kindstring- status, label or category
itemobject- changed in place
retourneHTMLElement

descriptionEditor(t, ro, bind)

mmo-kanban.jhs:2893

The description of a ticket: markdown, in <mmo-markdown-editor> (a plain textarea when the page does not have it). A ticket that has one opens on its preview, to be read; # suggests the board's tickets, @ the people it is assigned to.

descriptionEditor(t, ro, bind)
tobject- the ticket being edited, changed in place
roboolean
bindfunction- binds a plain control to a field of the ticket
retourneHTMLElement

addTriggers(editor, id, people)

mmo-kanban.jhs:2918

# suggests the board's tickets, @ the people: the ones tickets are assigned to, and more.

addTriggers(editor, id, people = () => [])
editorHTMLElement- an <mmo-markdown-editor>
id?string- the ticket written about, which # leaves out
people = () => []function():string[]- more people to suggest
retournevoid

discussionSection(editor)

mmo-kanban.jhs:2947

Start the discussion of an editor's ticket: its state lives in editor.talk, its section is drawn by

discussionSection(editor)
Voir
drawDiscussion, and its comments are loaded now.
editorobject
retourneHTMLElementthe section

loadDiscussion(editor)

asyncmmo-kanban.jhs:2976

(Re)load the comments of an editor's ticket.

async loadDiscussion(editor)
editorobject
retournePromise<void>

normalizeComment(c)

mmo-kanban.jhs:2996
normalizeComment(c)
cobject- a comment, as the discussion gave it
retourneobjecta comment the board can use, whatever it was given

countComments(editor)

mmo-kanban.jhs:3012

the card says how many comments its ticket has

countComments(editor)
editor

drawDiscussion(editor)

mmo-kanban.jhs:3027

Draw an editor's discussion: its header (the count, the order, reload), its comments, and the editor of a new one.

drawDiscussion(editor)
editorobject
retournevoid

commentList(editor)

mmo-kanban.jhs:3075

The comments, in the viewer's order: by date, or in threads -- a reply under what it answers, a reply to a comment that is gone starting a thread of its own.

commentList(editor)
editorobject
retourneHTMLElement

commentNode(editor, c, byId, sayParent)

mmo-kanban.jhs:3122

A comment: who wrote it and when, what it says, and what the viewer can do with it.

commentNode(editor, c, byId, sayParent)
editorobject
cobject- the comment
byIdMap<string, object>- the discussion's comments
sayParentboolean- whether to say which comment it answers
retourneHTMLElement

commentEditor(editor, kind, target)

mmo-kanban.jhs:3195

The editor of a comment: a new one, a reply, or a change of one's own.

commentEditor(editor, kind, target)
editorobject
kindstring- new, reply or edit
target?string- the comment answered or changed
retourneHTMLElement

focusComposer(editor, key)

mmo-kanban.jhs:3243

put the caret in a comment's editor, once it is drawn

focusComposer(editor, key)
editor
key

sendComment(editor, kind, target)

asyncmmo-kanban.jhs:3260

Send what a comment's editor holds: a new comment, a reply, or a change.

async sendComment(editor, kind, target)
editorobject
kindstring- new, reply or edit
target?string
retournePromise<void>

removeComment(editor, c)

asyncmmo-kanban.jhs:3302

Delete one's own comment, once asked: its replies stay, answering a deleted comment.

async removeComment(editor, c)
editorobject
cobject
retournePromise<void>

showComment(editor, id)

mmo-kanban.jhs:3322

scroll to a comment of the discussion, and make it flash

showComment(editor, id)
editor
id

storedOrder()

mmo-kanban.jhs:3337
storedOrder()
retournestringthe order the viewer picked last, threads unless they did

initials(name)

mmo-kanban.jhs:3362
initials(name)
name
retournestringwhat stands for someone without a picture: MM for marc-mouret

conditionEditor(t, node, set, redraw, preview, root)

mmo-kanban.jhs:3376

The editor of one condition, and of the ones it holds.

conditionEditor(t, node, set, redraw, preview, root = false)
tobject- the ticket being edited
node?object
setfunction(?object):void- puts a new node in its place, null removes it
redrawfunction():void- draws the whole tree again, after a change of its shape
previewHTMLElement- the description to update after a change of a value
root = falseboolean
retourneHTMLElement

convertCondition(t, node, type)

mmo-kanban.jhs:3482

a condition turned into another type, keeping what both share

convertCondition(t, node, type)
t
node
type

save(t, isNew)

mmo-kanban.jhs:3499

Save a ticket being edited.

save(t, isNew)
tobject- the edited copy
isNewboolean
retourneok: boolean, reasons: string[], id: ?string}

configureBoard(lists)

mmo-kanban.jhs:3524

Change the board's statuses, labels and categories. A ticket whose status goes takes the first status left of the same type; a label or a category that goes leaves its tickets. A status changing type stamps its tickets as a move would, so the change is refused when it breaks a constraint.

configureBoard(lists)
listsobject- {statuses, labels, categories}, each [{id, label}] (a status also has type and limit); an item without id is new; a list left out is kept
retourneok: boolean, reasons: string[]}

editSettings()

mmo-kanban.jhs:3587

Open the board's settings: its statuses, labels and categories.

editSettings()
retournevoid

notify(title, lines, tone)

mmo-kanban.jhs:3700

Say something for a while, under the toolbar.

notify(title, lines = [], tone = 'info')
titlestring
lines = []string[]
tone = 'info'string- bad, warn or info

Slots1

(default)

mmo-kanban.jhs

a <script type="application/json"> holding the board's data

<slot>