App-karr
view release on metacpan or search on metacpan
lib/App/karr/Cmd/Board.pm view on Meta::CPAN
my $hide = $status eq 'done' && !$self->done;
my %col = (
status => $status,
count => scalar @$tasks_in_status,
tasks => $hide ? [] : [ map { $_->to_frontmatter } @$tasks_in_status ],
);
push @{$board_data{columns}}, \%col;
}
$self->print_json(\%board_data);
return;
}
if ($self->compact) {
for my $status (@statuses) {
my $tasks_in_status = $by_status{$status} // [];
my $count = scalar @$tasks_in_status;
my $ids = join(',', map { $_->id } @$tasks_in_status);
printf "%s(%d): %s\n", $status, $count, $ids || '-';
}
return;
}
my $board_name = $ec->{board}{name} // 'Kanban Board';
# Colour only when writing to a real terminal â piped or redirected output
# stays clean plaintext so the board diffs, greps, and pastes cleanly.
my $color = -t STDOUT && !$ENV{NO_COLOR};
my $c = sub {
my ($text, $spec) = @_;
return $color ? colored($text, $spec) : $text;
};
my $sep = $c->('|', 'bright_black');
print $c->("# $board_name", 'bold cyan'), "\n";
# Skip empty archived unless it has tasks; hide done unless --done was given
# (the footer still notes how many done tasks were hidden).
my @display_statuses = grep {
($_ ne 'archived' || @{$by_status{$_} // []})
&& ($_ ne 'done' || $self->done)
} @statuses;
for my $status (@display_statuses) {
my $tasks = $by_status{$status} // [];
my $label = join ' ', map { ucfirst } split /-/, $status;
my $accent = $STATUS_COLOR{$status} // 'white';
print "\n", $c->("## $label", "bold $accent"), "\n";
for my $t (@$tasks) {
my @meta;
if ($t->priority && $t->priority ne 'medium') {
push @meta, $c->('priority:' . $t->priority, $PRIORITY_COLOR{$t->priority} // 'white');
}
# A claim is only worth showing while the work is still live, and which
# columns count as finished is the board's decision -- a board imported
# from kanban-md can end in `shipped`, and every finished card there
# still carried its claimant into the board (ticket #98, following #67).
if ($t->has_claimed_by && !$self->store->is_terminal_status($t->status)) {
push @meta, $c->('@' . $t->claimed_by, 'cyan');
}
if ($t->has_blocked) {
my $reason = $t->has_block_reason ? $t->block_reason : undef;
$reason = substr($reason, 0, 40) . '...' if defined $reason && length $reason > 43;
push @meta, $c->(
defined $reason && length $reason ? "blocked:$reason" : 'blocked', 'bold red');
}
if ($t->has_due) {
push @meta, $c->('due:' . $t->due, 'yellow');
}
my $line = join ' ', $c->('-', 'bright_black'), $t->id, $sep, $t->title;
$line .= " $sep " . join(" $sep ", @meta) if @meta;
print $line, "\n";
if ($self->tags && @{$t->tags}) {
print ' ', $c->(join(' ', map { "#$_" } @{$t->tags}), 'bright_black'), "\n";
}
}
}
# Summary footer
my $blocked = grep { $_->has_blocked } @tasks;
# Same test as the per-card `@claimant` token above, so the footer can never
# count a claim the board itself does not show.
my $claimed = grep { $_->has_claimed_by && !$self->store->is_terminal_status($_->status) } @tasks;
my $done_hidden = $self->done ? 0 : scalar @{ $by_status{done} // [] };
my $total_label = scalar(@tasks) . ' tasks';
$total_label .= " ($done_hidden done hidden)" if $done_hidden;
my @summary = ( $total_label );
push @summary, "$claimed claimed" if $claimed;
push @summary, "$blocked blocked" if $blocked;
print "\n", $c->(join(' ', @summary), 'bold'), "\n";
}
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
App::karr::Cmd::Board - Show board summary
=head1 VERSION
version 0.500
=head1 SYNOPSIS
karr board
karr board --tags
karr board --compact
karr board --json
karr board --done
=head1 DESCRIPTION
Renders a board-oriented summary grouped by status. The default output is a
compact, Markdown-flavoured plaintext board: the board name as an C<#> heading,
each status as a C<##> section, and one C<- id | title | meta...> line per task.
This stays readable when piped, redirected, diffed, or pasted. Colour is added
only when standard output is a terminal (and C<NO_COLOR> is unset). Compact and
JSON modes remain available for automation and scripting.
=head1 OUTPUT MODES
=over 4
=item * Default output
Lists every status as a C<## Status> section (in board order, empty sections
included; an empty C<archived> is hidden, and C<done> is hidden unless C<--done>
is given). Each task renders as C<- id | title> followed by C<priority>
(non-default only), C<@claimant>, C<blocked:reason>, and C<due:date> tokens where
applicable. A footer line totals tasks, claims, and blocks, and â when the
C<done> section is hidden and non-empty â appends a C<(N done hidden)> hint so
the count is not silently lost.
=item * C<--tags>
Adds an extra indented line of C<#tag> tokens beneath each task that has tags.
=item * C<--done>
Includes the C<done> section, which is hidden by default, and suppresses the
hidden-count footer hint. Applies to the default, C<--tags>, and C<--json>
renderings; C<--compact> always lists every status regardless.
=item * C<--compact>
Prints one line per status in the form C<status(count): ids>.
=item * C<--json>
Emits the board name, total task count, and a structured C<columns> array with
per-status task lists.
=back
=head1 SEE ALSO
L<karr>, L<App::karr>, L<App::karr::Cmd::List>, L<App::karr::Cmd::Show>,
L<App::karr::Cmd::Pick>, L<App::karr::Cmd::Context>
=head1 SUPPORT
=head2 Issues
Please report bugs and feature requests on GitHub at
L<https://github.com/Getty/karr/issues>.
=head2 IRC
Join C<#langertha> on C<irc.perl.org> or message Getty directly.
=head1 CONTRIBUTING
Contributions are welcome! Please fork the repository and submit a pull request.
=head1 AUTHOR
Torsten Raudssus <getty@cpan.org>
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2026 by Torsten Raudssus <torsten@raudssus.de> L<https://raudssus.de/>.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut
( run in 3.915 seconds using v1.01-cache-2.11-cpan-788537b7465 )