Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: v0.11.0 #19

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions .tpm
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ team:
fte: 1
timeline:
v0.11.0:
deadline: 2024-11-21 21:00:00 GMT+0200
deadline: 2024-11-25 12:00:00 GMT+0200
v0.10.0:
deadline: 2024-11-17 21:00:00 GMT+0200
deadline: 2024-11-17 23:40:00 GMT+0200
v0.9.0:
deadline: 2024-11-10 23:00:00 GMT+0200
v0.8.0:
Expand All @@ -29,33 +29,34 @@ timeline:
v0.2.0:
deadline: 2024-09-04 17:30:00 GMT+0200
tasks: |
[-:031:v0.12.0] Fix task output on hierarchy mode @vlad.k
[+:030:v0.10.0] Implement deadline class @vlad.k
[-:029:v0.11.0] Implement config command via source class @vlad.k
[-:028:v0.11.0] Tasks spill over batch mode @vlad.k
[-:029:v0.12.0] Implement config command via source class @vlad.k
[-:028:v0.12.0] Tasks spill over batch mode @vlad.k
[+:027:v0.10.0] Implement team/member section as classes @vlad.k
[+:026:v0.9.0] Implement srs section as classes @vlad.k
[+:025:v0.9.0] Show SRS in UI @vlad.k
[-:024:v0.11.0] Tweak task status based on child tasks (normalise) @vlad.k
[-:024:v0.12.0] Tweak task status based on child tasks (normalise) @vlad.k
[+:023:v0.9.0] Implement project, team, srs section as classes @vlad.k
[+:022:v0.7.0] Describe command - project @vlad.k
[+:021:v0.6.0] Add project description section @vlad.k
[+:020:v0.5.0] Add option to display tasks with different statuses: --backlog, --dev, --done @vlad.k
[+:019:v0.5.0] Add component as optional parameter for ls command @vlad.k
[-:018:v0.11.0] Generate snapshot @vlad.k
[-:018:v0.12.0] Generate snapshot @vlad.k
[+:017:v0.5.0] Add SRS section @vlad.k
[-:016:v0.11.0] Add describe command with resolved links @vlad.k
[-:016:v0.12.0] Add describe command with resolved links @vlad.k
[x:015:v0.5.0] Integrate .tpm folder at repository root level to store snapshots @vlad.k
[-:014:v0.11.0] Update README.md with Hello World section using <https://github.com/project-talan/tln-demo> repository @vlad.k
[-:014:v0.12.0] Update README.md with Hello World section using <https://github.com/project-talan/tln-demo> repository @vlad.k
[+:013:v0.6.0] Add search @vlad.k
[+:012:v0.6.0] Add CI/CD @vlad.k
[+:011:v0.6.0] Add unit test framework @vlad.k
[+:010:v0.6.0] Extract tags, timeline from task description @vlad.k
[+:009:v0.5.0] Add command to generate .todo template --team, --timeline, --tasks, --force @vlad.k
[+:008:v0.6.0] Merge multiple descriptions from one file @vlad.k
[-:007:v0.11.0] Server command: express server + fs watch @vlad.k
[-:007:v0.12.0] Server command: express server + fs watch @vlad.k
[+] Create API using express
[+] Implement web part: Dashboard
[-] Implement web part: Timeline
[>] Implement web part: Timeline
[-] Implement web part: Team
[-] Add --watch option to watch for changes in .todo file and refresh tpm internal state
[+:006:v0.4.0] Extract status, id, assingees from task description @vlad.k
Expand Down
67 changes: 64 additions & 3 deletions cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const findUp = require('find-up')
const yargs = require('yargs/yargs')
const { hideBin } = require('yargs/helpers');
const yaml = require('yaml');
const { dump } = require('js-yaml');

const getApp = async (argv, load, fn) => {
const verbose = argv.verbose;
Expand Down Expand Up @@ -53,6 +54,8 @@ yargs(hideBin(process.argv))
.option('srs', { describe: 'Include SRS section', default: false, type: 'boolean' })

.option('force', { describe: 'Force command execution', default: false, type: 'boolean' })
.option('json', { describe: 'Output in json format', default: false, type: 'boolean' })
.option('yaml', { describe: 'Output in yaml format', default: false, type: 'boolean' })
.option('hierarchy', { describe: 'Output nested components as hierarchy', default: false, type: 'boolean' })
//
// ls command aims to work exclusively with tasks
Expand All @@ -65,13 +68,71 @@ yargs(hideBin(process.argv))
}, async (argv) => {
getApp(argv, true, async (a) => {
// console.log(argv);
await a.ls({
const component = await a.ls({
component: argv.component,
depth: argv.depth,
who: { assignees: argv.assignee, all: argv.all },
filter: { tag: argv.tag, search: argv.search, deadline: argv.deadline, status: { backlog: argv.backlog, dev: argv.dev, done: argv.done } },
hierarchy: argv.hierarchy
filter: { tag: argv.tag, search: argv.search, deadline: argv.deadline, status: { backlog: argv.backlog, dev: argv.dev, done: argv.done } }
});
//
const hierarchy = argv.hierarchy;
if (component) {
if (argv.json || argv.yaml) {
if (argv.json) {
a.logger.con(JSON.stringify(component));
} else {
a.logger.con(yaml.stringify(component));
}
} else {
const dump = (c, indent, last) => {
// title
let ti = ` `;
let percentage = '';
if (c.tasks.length) {
percentage = Math.round(c.tasks.reduce((acc, t) => acc + t.percentage, 0) / c.tasks.length);
if (percentage > 0) {
percentage = `(${percentage}%)`;
} else {
percentage = '';
}
}
if (hierarchy) {
ti = `${indent}` + ((last && c.components.length === 0) ? ' ' : '│')
const title = (c.id) ? `${indent}${last?'└':'├'} ${c.id}` : '';
a.logger.con(`${title} ${percentage}`);
} else {
if (c.tasks.length) {
a.logger.con();
a.logger.con(`~ ${c.relativePath} ${percentage}`);
}
}
// tasks
const out = (task, indent) => {
if (task.title) {
const g = task.assignees.length ? ` @(${task.assignees.join(',')})` : '';
const tg = task.tags.length ? ` #(${task.tags.join(',')})` : '';
const dl = task.deadline ? ` (${task.deadline})` : '';
const id = task.id ? ` ${task.id}:` : '';
a.logger.con(`${indent}${task.status}${id} ${task.title}${g}${tg}${dl}`);
}
// console.log(task);
for (const t of task.tasks) {
out(t, `${indent} `);
}
}
for (const t of c.tasks) {
out(t, ti);
}
// components
const lng = c.components.length;
for (let i = 0; i < lng; i++) {
const lc = (i === lng - 1);
dump(c.components[i], indent + (last? ' ' : '│ '), lc);
}
}
dump(component, '', true);
}
}
});
})
//
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tln-pm",
"version": "0.10.0",
"version": "0.11.0",
"description": "Project Management as Code",
"main": "cli.js",
"scripts": {
Expand Down
4 changes: 2 additions & 2 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class App {
}

async ls(options) {
const {component, depth, who, filter, hierarchy} = options;
const {component, depth, who, filter} = options;
let aees = [...who.assignees];
//
// console.log(options, who.all || aees.length);
Expand All @@ -84,7 +84,7 @@ class App {
if (who.all || aees.length) {
const c = await this.getCurrentComponent(component);
if (c) {
await c.ls({depth, who: {...who, assignees: aees}, filter, hierarchy, indent: '', last: true});
return await c.ls({depth, who: {...who, assignees: aees}, filter});
}
}
}
Expand Down
47 changes: 17 additions & 30 deletions src/component.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,10 +176,16 @@ class Component {
}

async ls(options) {
const {depth, who, filter, hierarchy, indent, last} = options;
const {depth, who, filter} = options;
const who2 = { ...who, assignees: await this.getAssignees(who.assignees)};
//
const ts = {
id: this.id,
relativePath: this.getRelativePath(),
tasks: [],
components: []
};
// tasks
const ts = { tasks: [] };
for (const task of this.tasks) {
const t = await task.filter({who: who2, filter});
//console.log(t);
Expand All @@ -188,39 +194,20 @@ class Component {
}
};
//
if (ts && ts.tasks.length) {
let ti = ' ';
if (hierarchy) {
ti = `${indent}${ti}`;
const title = (this.id) ? `${indent}${last?'└':'├'} ${this.id}` : '';
const summary = '45%';
this.logger.con(`${title} ${summary}`);
} else {
this.logger.con();
this.logger.con(`~ ${this.getRelativePath()}`);
}
const out = (task, indent) => {
if (task.title) {
const a = task.assignees.length ? ` @(${task.assignees.join(',')})` : '';
const tg = task.tags.length ? ` #(${task.tags.join(',')})` : '';
const dl = task.deadline ? ` (${task.deadline})` : '';
const id = task.id ? ` ${task.id}:` : '';
this.logger.con(`${indent}${task.status}${id} ${task.title}${a}${tg}${dl}`);
}
for (const t of task.tasks) {
out(t, `${indent} `);
}
}
out(ts, '');
}
// about components
// nested components
if (depth) {
const lng = this.components.length;
for (let i = 0; i < lng; i++) {
const lc = (i === lng - 1);
await this.components[i].ls({depth: depth - 1, who: who2, filter, hierarchy, indent: indent + (last? ' ' : '│ '), last: lc});
const cp = await this.components[i].ls({depth: depth - 1, who: who2, filter});
if (cp) {
ts.components.push(cp);
}
}
}
//
if (ts.tasks.length || ts.components.length) {
return ts;
}
}

async describeProject(options) {
Expand Down
8 changes: 8 additions & 0 deletions src/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ class Server {
root.getTeam(team, true, true)
res.send(this.makeResponce(team));
})
ea.get('/tasks', async(req, res) => {
res.send(this.makeResponce( await app.ls({
component: null,
depth: 10,
who: { assignees: [], all: true },
filter: { tag: [], search: [], deadline: [], status: { backlog: true, dev: true, done: false } }
})));
})
ea.get('/srs', async(req, res) => {
res.send(this.makeResponce( await app.describe({ what: { srs: true } })));
})
Expand Down
13 changes: 9 additions & 4 deletions src/task.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class Task {
this.source = source;
this.parent = parent;
this.indent = indent;
this.status = '-';
this.status = '';
this.id = null;
this.title = '';
this.deadline = '';
Expand Down Expand Up @@ -55,7 +55,7 @@ class Task {
this.links = links;
}

async filter(options, alsoMe = false, alsoTags = false) {
async filter(options, alsoMe = false, alsoTags = false, statusToo = false) {
//console.log('filter in', this.id);
const {who, filter} = options;
// check myself
Expand All @@ -65,22 +65,27 @@ class Task {
{ statuses: ['-', '?', '!'], flag: filter.status.backlog },
{ statuses: ['>'], flag: filter.status.dev },
{ statuses: ['+', 'x'], flag: filter.status.done },
].find(v => v.flag && v.statuses.includes(this.status) );
].find(v => v.flag && v.statuses.includes(this.status) ) || statusToo;
//
const tags = [this.deadline].concat(this.tags);
const tg = (filter.tag.length ? filter.tag.find( t => tags.includes(t) ) : true) || alsoTags;
//
const sr = filter.search.length ? filter.search.find( s => this.title.indexOf(s) >= 0 ) : true;
//
// console.log(this.id, 'me', me, 'st', st, 'tg', tg, 'sr', sr);
const tasks = (await Promise.all(this.tasks.map(async t => t.filter(options, me, tg)))).filter(v => !!v);
const tasks = (await Promise.all(this.tasks.map(async t => t.filter(options, me, tg, st)))).filter(v => !!v);
let percentage = (this.status === '+' || this.status === 'x') ? 100 : 0;
if (this.tasks.length) {
percentage = Math.round(tasks.reduce((acc, t) => acc + t.percentage, 0) / tasks.length);
}
//console.log(this.id, st, who.all, me, tg, sr, tasks.length);
if (((who.all || me) && st && tg && sr) || tasks.length) {
//console.log('filter out', this.id);
return {
status: this.status,
id: this.id,
title: this.title,
percentage,
deadline: this.deadline,
assignees: this.assignees,
tags: this.tags,
Expand Down
12 changes: 6 additions & 6 deletions web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.1/chart.umd.js" integrity="sha512-ZwR1/gSZM3ai6vCdI+LVF1zSq/5HznD3ZSTk7kajkaj4D292NLuduDCO1c/NT8Id+jE58KYLKT7hXnbtryGmMg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/markdown-it/13.0.2/markdown-it.min.js" referrerpolicy="no-referrer"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/markdown-it.min.js"></script>
<script src="https://code.highcharts.com/gantt/highcharts-gantt.js"></script>
<script>
import('https://cdn.jsdelivr.net/npm/[email protected]/fp/cdn.min.js').then((dateFns) => {
console.log(dateFns);
Expand All @@ -30,13 +31,12 @@
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">

<ul class="navbar-nav me-auto mb-2 mb-lg-0" id="myTab" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="dashboard-tab" data-bs-toggle="tab" data-bs-target="#dashboard-tab-pane" type="button" role="tab" aria-controls="dashboard-tab-pane" aria-selected="true">Dashboard</button>
<button class="nav-link" id="dashboard-tab" data-bs-toggle="tab" data-bs-target="#dashboard-tab-pane" type="button" role="tab" aria-controls="dashboard-tab-pane" aria-selected="true">Dashboard</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="timeline-tab" data-bs-toggle="tab" data-bs-target="#timeline-tab-pane" type="button" role="tab" aria-controls="timeline-tab-pane" aria-selected="false">Timeline</button>
<button class="nav-link active" id="timeline-tab" data-bs-toggle="tab" data-bs-target="#timeline-tab-pane" type="button" role="tab" aria-controls="timeline-tab-pane" aria-selected="false">Timeline</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="team-tab" data-bs-toggle="tab" data-bs-target="#team-tab-pane" type="button" role="tab" aria-controls="team-tab-pane" aria-selected="false">Team</button>
Expand Down Expand Up @@ -70,7 +70,7 @@
<!-- Tabs -->
<div class="tab-content" id="myTabContent">
<!-- Dashboard -->
<div class="tab-pane fade show active" id="dashboard-tab-pane" role="tabpanel" aria-labelledby="dashboard-tab" tabindex="0">
<div class="tab-pane fade" id="dashboard-tab-pane" role="tabpanel" aria-labelledby="dashboard-tab" tabindex="0">
<p class="fs-5 d-none">
<i class="bi bi-github"></i>
</p>
Expand All @@ -81,8 +81,8 @@
</div>
</div>
<!-- Timeline -->
<div class="tab-pane fade" id="timeline-tab-pane" role="tabpanel" aria-labelledby="timeline-tab" tabindex="0">
<p>Comming soon...</p>
<div class="tab-pane fade show active" id="timeline-tab-pane" role="tabpanel" aria-labelledby="timeline-tab" tabindex="0">
<div id="gantt"></div>
<div class="d-none" id="timeline_gantt_chart"></div>
</div>
<!-- Team -->
Expand Down
Loading