├── .gitignore ├── Template ├── table_view │ ├── position.php │ ├── reference.php │ ├── subtask.php │ ├── column.php │ ├── swimlane.php │ ├── priority.php │ ├── meta_magik.php │ ├── start_date.php │ ├── title.php │ ├── tag.php │ ├── other_assignees.php │ ├── task_id.php │ ├── assigned_group.php │ ├── due_date.php │ ├── sort_menu.php │ ├── category.php │ ├── assignee.php │ └── header.php ├── project_header │ └── views.php └── project_dashboard │ └── show.php ├── Screenshot └── 1.png ├── Asset ├── main.css ├── hide-list.js └── main.js ├── Locale └── zh_CN │ └── translations.php ├── LICENSE ├── config.default.php ├── Helper └── TableDataHelper.php ├── Controller ├── ExportController.php └── TableViewController.php ├── Plugin.php ├── README.md └── Model └── FieldDataModel.php /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /config.php 3 | -------------------------------------------------------------------------------- /Template/table_view/position.php: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Template/table_view/reference.php: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Template/table_view/subtask.php: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Template/table_view/column.php: -------------------------------------------------------------------------------- 1 | text->e($task['column_name']) ?> 2 | -------------------------------------------------------------------------------- /Template/table_view/swimlane.php: -------------------------------------------------------------------------------- 1 | text->e($task['swimlane_name']) ?> 2 | -------------------------------------------------------------------------------- /Screenshot/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greyaz/TableView/HEAD/Screenshot/1.png -------------------------------------------------------------------------------- /Template/table_view/priority.php: -------------------------------------------------------------------------------- 1 | task->renderPriority($task['priority']) ?> 2 | -------------------------------------------------------------------------------- /Asset/main.css: -------------------------------------------------------------------------------- 1 | #table-view .status-closed{ 2 | text-decoration:line-through; 3 | } 4 | 5 | -------------------------------------------------------------------------------- /Template/table_view/meta_magik.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Template/table_view/start_date.php: -------------------------------------------------------------------------------- 1 | 2 | dt->date($task['date_started']) ?> 3 | 4 | -------------------------------------------------------------------------------- /Locale/zh_CN/translations.php: -------------------------------------------------------------------------------- 1 | "表格", 5 | 'DESC' => "降序", 6 | 'ASC' => "升序", 7 | 'Export All' => "全部导出" 8 | ); 9 | -------------------------------------------------------------------------------- /Template/table_view/title.php: -------------------------------------------------------------------------------- 1 | url->link($this->text->e($task['title']), 'TaskViewController', 'show', array('task_id' => $task['id'])) ?> 2 | -------------------------------------------------------------------------------- /Template/table_view/tag.php: -------------------------------------------------------------------------------- 1 | 2 | "> 3 | text->e($tag['name']) ?> 4 | 5 | 6 | -------------------------------------------------------------------------------- /Template/table_view/other_assignees.php: -------------------------------------------------------------------------------- 1 | 0 && count($this->task->multiselectMemberModel->getMembers($task['owner_ms'])) > 0) : ?> 2 | helper->sizeAvatarHelperExtend->sizeMultiple($task['owner_ms'], 'avatar-inline avatar-bdyn', 20) ?> 3 | 4 | -------------------------------------------------------------------------------- /Template/table_view/task_id.php: -------------------------------------------------------------------------------- 1 | user->hasProjectAccess('TaskModificationController', 'edit', $task['project_id'])): ?> 2 | render('task/dropdown', array('task' => $task, 'redirect' => isset($redirect) ? $redirect : '')) ?> 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Asset/hide-list.js: -------------------------------------------------------------------------------- 1 | (function($){ 2 | if ($){ 3 | $(document).ready(function(){ 4 | var $listView = $(".views-switcher-component .views li .view-listing"); 5 | if ($listView.length == 1){ 6 | $listView.parent().hide(); 7 | } 8 | }); 9 | } 10 | })(typeof jQuery == "undefined" ? null: jQuery); 11 | -------------------------------------------------------------------------------- /Template/table_view/assigned_group.php: -------------------------------------------------------------------------------- 1 | 2 | text->e($task['assigned_groupname'] ?: $task['owner_gp']) ?> 3 | 4 | -------------------------------------------------------------------------------- /Template/table_view/due_date.php: -------------------------------------------------------------------------------- 1 | 2 | 9 | dt->datetime($task['date_due']) ?> 10 | 11 | 12 | -------------------------------------------------------------------------------- /Template/project_header/views.php: -------------------------------------------------------------------------------- 1 |
  • app->checkMenuSelection('TableViewController') ?>> 2 | url->icon('table', t('Table'), 'TableViewController', 'show', 3 | array( 4 | 'project_id' => $project['id'], 5 | 'search' => $filters['search'], 6 | 'plugin' => 'TableView' 7 | ), 8 | false, 9 | "table-view", 10 | t('Keyboard shortcut: "%s"', 'v t') 11 | ) ?> 12 |
  • 13 | 14 | -------------------------------------------------------------------------------- /Template/table_view/sort_menu.php: -------------------------------------------------------------------------------- 1 | 13 | -------------------------------------------------------------------------------- /Asset/main.js: -------------------------------------------------------------------------------- 1 | (function(KB){ 2 | if (KB){ 3 | KB.on('dom.ready', function () { 4 | function goToLink (selector) { 5 | if (! KB.modal.isOpen()) { 6 | var element = KB.find(selector); 7 | 8 | if (element !== null) { 9 | window.location = element.attr('href'); 10 | } 11 | } 12 | } 13 | 14 | KB.onKey('v+t', function () { 15 | goToLink('a.table-view'); 16 | }); 17 | }); 18 | } 19 | })(typeof KB == "undefined" ? null: KB); 20 | 21 | -------------------------------------------------------------------------------- /Template/table_view/category.php: -------------------------------------------------------------------------------- 1 | 2 | "> 3 | user->hasProjectAccess('TaskModificationController', 'edit', $task['project_id'])): ?> 4 | url->link( 5 | $this->text->e($task['category_name']), 6 | 'TaskModificationController', 7 | 'edit', 8 | array('task_id' => $task['id']), 9 | false, 10 | 'js-modal-medium' . (! empty($task['category_description']) ? ' tooltip' : ''), 11 | t('Change category') 12 | ) ?> 13 | 14 | app->tooltipMarkdown($task['category_description']) ?> 15 | 16 | 17 | text->e($task['category_name']) ?> 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Template/table_view/assignee.php: -------------------------------------------------------------------------------- 1 | 2 |
    3 | user->hasProjectAccess('TaskModificationController', 'edit', $task['project_id'])): ?> 5 | class="task-board-change-assignee" data-url="url->href('TaskModificationController', 'edit', array('task_id' => $task['id'])) ?>"> 6 | 7 | class="task-board-assignee"> 8 | 9 | avatar->small( 10 | $task['owner_id'], 11 | $task['assignee_username'], 12 | $task['assignee_name'], 13 | $task['assignee_email'], 14 | $task['assignee_avatar_path'], 15 | 'avatar-inline' 16 | ) ?> 17 | text->e($task['assignee_name'] ?: $task['assignee_username']) ?> 18 | 19 |
    20 | 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Yang Zhang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /config.default.php: -------------------------------------------------------------------------------- 1 | "Progress", 41 | ); 42 | -------------------------------------------------------------------------------- /Helper/TableDataHelper.php: -------------------------------------------------------------------------------- 1 | paginator 12 | ->setUrl('TableViewController', 'show', array( 13 | 'project_id' => $project_id, 14 | 'search' => $search, 15 | 'plugin' => 'TableView', 16 | 'csrf_token' => $this->token->getReusableCSRFToken() 17 | )) 18 | ->setMax($amount) 19 | ->setOrder($order) 20 | ->setDirection($direction) 21 | ->setFormatter($this->taskListSubtaskFormatter) 22 | ->setQuery($this->taskLexer 23 | ->build($search) 24 | ->withFilter(new TaskProjectFilter($project_id)) 25 | ->getQuery() 26 | ) 27 | ->calculate(); 28 | } 29 | 30 | 31 | } 32 | -------------------------------------------------------------------------------- /Controller/ExportController.php: -------------------------------------------------------------------------------- 1 | request->getStringParam('count'); 35 | $project_id = (int)$this->request->getStringParam('project_id'); 36 | $project = $this->getProject($project_id); 37 | $search = $this->helper->projectHeader->getSearchQuery($project); 38 | list($order, $direction) = $this->userSession->getListOrder($project_id); 39 | 40 | $paginator = $this->helper->tableDataHelper->getPaginator($project_id, $search, $count, $order, $direction); 41 | $tasks = $paginator->getCollection(); 42 | $data = $this->getData($tasks); 43 | 44 | $this->response->withFileDownload('tasks.csv'); 45 | $this->response->csv($data); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Plugin.php: -------------------------------------------------------------------------------- 1 | helper->register('tableDataHelper', '\Kanboard\Plugin\TableView\Helper\TableDataHelper'); 18 | 19 | $this->template->hook->attach('template:project-header:view-switcher', 'TableView:project_header/views'); 20 | $this->hook->on('template:layout:css', array('template' => 'plugins/TableView/Asset/main.css')); 21 | $this->hook->on('template:layout:js', array('template' => 'plugins/TableView/Asset/main.js')); 22 | 23 | if (!isset($configs["HIDE_LIST_VIEW"]) || $configs["HIDE_LIST_VIEW"] === true) 24 | { 25 | $this->hook->on('template:layout:js', array('template' => 'plugins/TableView/Asset/hide-list.js')); 26 | } 27 | } 28 | } 29 | 30 | public function onStartup() 31 | { 32 | Translator::load($this->languageModel->getCurrentLanguage(), __DIR__.'/Locale'); 33 | } 34 | 35 | public function getPluginName() 36 | { 37 | return 'TableView'; 38 | } 39 | 40 | public function getPluginDescription() 41 | { 42 | return t('A Kanboard plugin that provides a table view of tasks in your project.'); 43 | } 44 | 45 | public function getPluginAuthor() 46 | { 47 | return 'Greyaz'; 48 | } 49 | 50 | public function getPluginVersion() 51 | { 52 | return '0.2.0'; 53 | } 54 | 55 | public function getPluginHomepage() 56 | { 57 | return 'https://github.com/greyaz/TableView'; 58 | } 59 | } 60 | 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Table View 2 | A [Kanboard](https://github.com/kanboard/kanboard) plugin that provides a table view of tasks in your project. 3 | 4 | ![alt screenshot](Screenshot/1.png) 5 | 6 | ## Features 7 | 1. Hide orignal list view or not 8 | 2. Customizable table fields 9 | 3. Compatible with the plugins "Group_assigne" and "metaMagik" 10 | 4. Export tasks 11 | 12 | ## Getting started 13 | 1. Install from the Kanboard plugin manager directly. Or clone this repository to your plugin folder. 14 | 2. Copy and rename the file `config.default.php` to `config.php`, then edit it by following the instructions in the comments. 15 | 16 | ## Configuration Items 17 | 18 | **$configs["HIDE_LIST_VIEW"] : Boolean** 19 | > Hide the list view or not. Default: true 20 | > ```php 21 | > $configs["HIDE_LIST_VIEW"] = true; 22 | > ``` 23 | 24 |
    25 | 26 | **$configs["TABLE_FIELDS"] : Array** 27 | > The fields display in the table by the sequence in this array. 28 | > ```php 29 | > $configs["TABLE_FIELDS"] = array( 30 | > "::PRIORITY", "::TASK_ID", "::TITLE", "::COLUMN", "::ASSIGNEE", "::DUE_DATE", "::METAMAGIK::expected_launch_date" 31 | > ); 32 | > ``` 33 | > The following keywords are supported by default: 34 | > - ::ASSIGNEE 35 | > - ::CATEGORY 36 | > - ::COLUMN 37 | > - ::DUE_DATE 38 | > - ::PRIORITY 39 | > - ::POSITION 40 | > - ::REFERENCE 41 | > - ::START_DATE 42 | > - ::SUBTASK_NUMBER 43 | > - ::SWIMLANE 44 | > - ::TAG 45 | > - ::TASK_ID 46 | > - ::TITLE 47 | > 48 | > The following keywords are supported after installing the plugin "Group_assign": 49 | > - ::ASSIGNED_GROUP 50 | > - ::OTHER_ASSIGNEES 51 | > 52 | > If the plugin "metaMagik" is installed, your custom field can be loaded via the prefix "::METAMAGIK::" with your field name. Example: 53 | > - ::METAMAGIK::expected_launch_date 54 | 55 |
    56 | 57 | **$configs["CUSTOMIZED_FIELD_NAMES"] : Array** 58 | > Optional. Customize the names of the fields. Example: 59 | > ```php 60 | > $configs["CUSTOMIZED_FIELD_NAMES"] = array( 61 | > "::COLUMN" => "Progress", 62 | > ); 63 | > ``` 64 | 65 | ## Author 66 | Greyaz 67 | 68 | ## License 69 | License MIT 70 | -------------------------------------------------------------------------------- /Controller/TableViewController.php: -------------------------------------------------------------------------------- 1 | fieldDataModel = new FieldDataModel($c); 17 | } 18 | 19 | public function show() 20 | { 21 | $project = $this->getProject(); 22 | $search = $this->helper->projectHeader->getSearchQuery($project); 23 | 24 | $req_direction = $this->request->getStringParam('direction'); 25 | $req_order = $this->request->getStringParam('order'); 26 | if (!empty($req_direction) || !empty($req_order)) { 27 | $this->checkReusableGETCSRFParam(); 28 | } 29 | 30 | list($order, $direction) = $this->userSession->getListOrder($project['id']); 31 | if (!empty($req_direction)){ 32 | $direction = $req_direction; 33 | } 34 | if (!empty($req_order)){ 35 | $order = $req_order; 36 | } 37 | $this->userSession->setListOrder($project['id'], $order, $direction); 38 | 39 | $paginator = $this->helper->tableDataHelper->getPaginator($project['id'], $search, 30, $order, $direction); 40 | $fieldNames = array(); 41 | foreach($GLOBALS["configs"]["TABLE_FIELDS"] as $field){ 42 | $fieldNames[] = $this->fieldDataModel->getName($field); 43 | } 44 | 45 | $this->response->html($this->helper->layout->app('TableView:project_dashboard/show', array( 46 | 'project' => $project, 47 | 'title' => $project["name"], 48 | 'description' => $this->helper->projectHeader->getDescription($project), 49 | 'paginator' => $paginator, 50 | 'fields' => $GLOBALS["configs"]["TABLE_FIELDS"], 51 | 'field_names' => $fieldNames, 52 | 'order' => $order, 53 | 'direction' => $direction, 54 | 'all_sorts' => $this->fieldDataModel->getAllSorts(), 55 | ))); 56 | } 57 | } 58 | 59 | -------------------------------------------------------------------------------- /Template/table_view/header.php: -------------------------------------------------------------------------------- 1 |
    2 |
    3 | 4 | getTotal() > 1): ?> 5 | getTotal()) ?> 6 | 7 | getTotal()) ?> 8 | 9 | 10 |
    11 | 14 | 15 | user->hasProjectAccess('TaskModificationController', 'save', $project['id'])): ?> 16 | 19 |
    20 | -  21 | 32 |
    33 | 34 | 35 |
    36 | render('TableView:table_view/sort_menu', array('paginator' => $paginator, 'all_sorts' => $all_sorts,)) ?> 37 |
    38 |
    39 | -------------------------------------------------------------------------------- /Model/FieldDataModel.php: -------------------------------------------------------------------------------- 1 | defaultNames = array( 14 | "::ASSIGNEE" => array("name" => t("Assignee"), "sort" => "assignee_name"), 15 | "::CATEGORY" => array("name" => t("Category"), "sort" => "category_name"), 16 | "::COLUMN" => array("name" => t("Column"), "sort" => "column_name"), 17 | "::DUE_DATE" => array("name" => t("Due date"), "sort" => \Kanboard\Model\TaskModel::TABLE.".date_due"), 18 | "::PRIORITY" => array("name" => t("Priority"), "sort" => \Kanboard\Model\TaskModel::TABLE.".priority"), 19 | "::POSITION" => array("name" => t("Position"), "sort" => \Kanboard\Model\TaskModel::TABLE.".position"), 20 | "::REFERENCE" => array("name" => t("Reference"), "sort" => \Kanboard\Model\TaskModel::TABLE.".reference"), 21 | "::START_DATE" => array("name" => t("Start date"), "sort" => \Kanboard\Model\TaskModel::TABLE.".date_started"), 22 | "::SUBTASK_NUMBER" => array("name" => t("Subtask"), "sort" => ""), 23 | "::SWIMLANE" => array("name" => t("Swimlane"), "sort" => "swimlane_name"), 24 | "::TAG" => array("name" => t("Tag"), "sort" => ""), 25 | "::TASK_ID" => array("name" => t("Task ID"), "sort" => \Kanboard\Model\TaskModel::TABLE.".id"), 26 | "::TITLE" => array("name" => t("Title"), "sort" => \Kanboard\Model\TaskModel::TABLE.".title"), 27 | "::ASSIGNED_GROUP" => array("name" => t("Assigned Group"), "sort" => ""), 28 | "::OTHER_ASSIGNEES" => array("name" => t("Other Assignees"), "sort" => ""), 29 | ); 30 | } 31 | 32 | public function getName($field){ 33 | if (!empty($GLOBALS["configs"]["CUSTOMIZED_FIELD_NAMES"][$field])){ 34 | return $GLOBALS["configs"]["CUSTOMIZED_FIELD_NAMES"][$field]; 35 | } 36 | if (!empty($this->defaultNames[$field])){ 37 | return $this->defaultNames[$field]["name"]; 38 | } 39 | $splited = explode("::METAMAGIK::", $field); 40 | if ($splited[0] != $field){ 41 | return str_replace("_", " ", $splited[1]); 42 | } 43 | return $field; 44 | } 45 | 46 | public function getAllSorts(){ 47 | $sortList = array(); 48 | foreach($this->defaultNames as $key => $value){ 49 | $sortList[$this->getName($key)] = $this->defaultNames[$key]["sort"]; 50 | } 51 | return $sortList; 52 | } 53 | } 54 | 55 | -------------------------------------------------------------------------------- /Template/project_dashboard/show.php: -------------------------------------------------------------------------------- 1 |
    2 | projectHeader->render($project, 'TableViewController', 'show', false, 'TableView') ?> 3 | 67 |
    68 | --------------------------------------------------------------------------------