Rework the task list layout

This commit reworks the task list layout so that tasks are arranged
by project and branch. The rows in the list are also modified to make
space for the addition of new fields in future. One effect of this is
that task notes can now be viewed and edited inline.

Change-Id: I8694c906c0a5f3567331574ec3a516dec586414a
This commit is contained in:
Adam Coldrick 2016-08-18 15:25:51 +00:00
parent 275780922d
commit cfc3211185
12 changed files with 572 additions and 365 deletions

View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2016 Codethink Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
/**
* The angular resource abstraction that allows us to access branches and their
* details.
*
* @see ResourceFactory
* @author Adam Coldrick
*/
angular.module('sb.services').factory('Branch',
function (ResourceFactory) {
'use strict';
var resource = ResourceFactory.build(
'/branches/:id',
'/branches/search',
{id: '@id'}
);
ResourceFactory.applySearch(
'Branch',
resource,
'name',
{Text: 'q'}
);
return resource;
});

View File

@ -20,9 +20,9 @@
angular.module('sb.story').controller('StoryDetailController',
function ($log, $rootScope, $scope, $state, $stateParams, $modal, Session,
Preference, TimelineEvent, Comment, TimelineEventTypes, story,
Story, creator, tasks, Task, DSCacheFactory, User, $q,
storyboardApiBase, SessionModalService, moment, $document,
$anchorScroll, $timeout, $location, currentUser,
Story, Project, Branch, creator, tasks, Task, DSCacheFactory,
User, $q, storyboardApiBase, SessionModalService, moment,
$document, $anchorScroll, $timeout, $location, currentUser,
enableEditableComments, Tags) {
'use strict';
@ -55,8 +55,48 @@ angular.module('sb.story').controller('StoryDetailController',
*
* @type {[Task]}
*/
$scope.projectNames = [];
$scope.projects = {};
$scope.tasks = tasks;
function mapTaskToProject(task) {
Project.get({id: task.project_id}).$promise.then(function(project) {
var idx = $scope.projectNames.indexOf(project.name);
if (idx < 0) {
$scope.projectNames.push(project.name);
$scope.projects[project.name] = project;
$scope.projects[project.name].branchNames = [];
$scope.projects[project.name].branches = {};
}
Branch.get({id: task.branch_id}).$promise.then(
function(branch) {
var branchIdx = $scope.projects[project.name]
.branchNames.indexOf(branch.name);
if (branchIdx > -1) {
$scope.projects[project.name].branches[branch.name]
.tasks.push(task);
} else {
$scope.projects[project.name]
.branches[branch.name] = branch;
$scope.projects[project.name]
.branches[branch.name].tasks = [task];
$scope.projects[project.name]
.branches[branch.name].newTask = new Task({
story_id: $scope.story.id,
branch_id: branch.id,
project_id: project.id,
status: 'todo',
priority: 'medium'
});
$scope.projects[project.name]
.branchNames.push(branch.name);
}
});
});
}
angular.forEach(tasks, mapTaskToProject);
// Load the preference for each display event.
function reloadPagePreferences() {
TimelineEventTypes.forEach(function (type) {
@ -498,20 +538,57 @@ angular.module('sb.story').controller('StoryDetailController',
/**
* Adds a task.
*/
$scope.createTask = function () {
$scope.createTask = function (task, branch) {
// Make a copy to save, so that the next task retains the
// old information (for easier continuous editing).
var savingTask = new Task(angular.copy($scope.newTask));
var savingTask = new Task(angular.copy(task));
savingTask.$save(function (savedTask) {
$scope.tasks.push(savedTask);
if (branch) {
branch.tasks.push(savedTask);
} else {
mapTaskToProject(savedTask);
}
$scope.loadEvents();
});
};
/**
* Cleans up the project/branch/task tree.
*
* If there are no tasks remaining in the given branch in the given
* project, then remove that branch from the project's list of
* branches to display tasks for.
*
* If there are then no branches left in the project, remove the
* project from the list of projects to display tasks for.
*/
function cleanBranchAndProject(projectName, branchName) {
var project = $scope.projects[projectName];
var branch = project.branches[branchName];
var nameIdx = -1;
if (branch.tasks.length === 0) {
nameIdx = project.branchNames.indexOf(branchName);
if (nameIdx > -1) {
project.branchNames.splice(nameIdx, 1);
}
delete project.branches[branchName];
}
if (project.branchNames.length === 0) {
nameIdx = $scope.projectNames.indexOf(projectName);
if (nameIdx > -1) {
$scope.projectNames.splice(nameIdx, 1);
}
delete $scope.projects[projectName];
}
}
/**
* Updates the task list.
*/
$scope.updateTask = function (task, fieldName, value) {
$scope.updateTask = function (task, fieldName, value, projectName,
branchName) {
var params = {id: task.id};
params[fieldName] = value;
task[fieldName] = value;
@ -519,33 +596,37 @@ angular.module('sb.story').controller('StoryDetailController',
Task.update(params, function() {
$scope.showTaskEditForm = false;
$scope.loadEvents();
}).$promise.then(function(updated) {
if (fieldName === 'project_id') {
var project = $scope.projects[projectName];
var branch = project.branches[branchName];
var branchTaskIndex = branch.tasks.indexOf(task);
if (branchTaskIndex > -1) {
branch.tasks.splice(branchTaskIndex, 1);
}
cleanBranchAndProject(projectName, branchName);
mapTaskToProject(updated);
}
});
}
};
/**
* Adds link/comment to task
*/
$scope.showTaskNotes = function(task) {
var modalInstance = $modal.open({
templateUrl: 'app/stories/template/task_notes.html',
controller: 'StoryTaskNotesController',
resolve: {
task: function() {
return task;
}
}
});
$scope.editNotes = function(task) {
task.tempNotes = task.link;
task.editing = true;
};
modalInstance.result.finally(function() {
$scope.loadEvents();
});
$scope.cancelEditNotes = function(task) {
task.tempNotes = '';
task.editing = false;
};
/**
* Removes this task
*/
$scope.removeTask = function (task) {
$scope.removeTask = function (task, projectName, branchName) {
var modalInstance = $modal.open({
templateUrl: 'app/stories/template/delete_task.html',
controller: 'StoryTaskDeleteController',
@ -567,6 +648,14 @@ angular.module('sb.story').controller('StoryDetailController',
if (taskIndex > -1) {
$scope.tasks.splice(taskIndex, 1);
}
var project = $scope.projects[projectName];
var branch = project.branches[branchName];
var branchTaskIndex = branch.tasks.indexOf(task);
if (branchTaskIndex > -1) {
branch.tasks.splice(branchTaskIndex, 1);
}
cleanBranchAndProject(projectName, branchName);
$scope.loadEvents();
}
);

View File

@ -1,83 +0,0 @@
/*
* Copyright (c) 2016 Codethink Ltd.
*
* Licensed under the Apache License, Version 2.0 (the 'License'); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
/**
* Controller for adding notes to tasks
*/
angular.module('sb.story').controller('StoryTaskNotesController',
function ($log, $scope, $state, task, $modalInstance, Task) {
'use strict';
$scope.task = angular.copy(task);
/**
* Generic service error handler. Assigns errors to the view's scope,
* and unsets our flags.
*/
function handleServiceError(error) {
// We've encountered an error.
$scope.error = error;
$scope.isLoading = false;
$scope.isUpdating = false;
}
/**
* Resets our loading flags.
*/
function handleServiceSuccess() {
$scope.isLoading = false;
$scope.isUpdating = false;
task.link = $scope.task.link;
}
/**
* Resets any changes and toggles the form back.
*/
$scope.cancel = function () {
$scope.editing = false;
$scope.task = angular.copy(task);
};
/**
* Scope method, invoke this when you want to update the task.
*/
$scope.update = function () {
// Set our progress flags and clear previous error conditions.
$scope.isUpdating = true;
$scope.error = {};
// Invoke the save method and wait for results.
var params = {
id: task.id,
link: $scope.task.link
};
Task.update(params, function () {
$modalInstance.close('save');
handleServiceSuccess();
},
handleServiceError
);
};
// Set our progress flags and clear previous error conditions.
$scope.close = function () {
$modalInstance.close('closed');
};
});

View File

@ -31,6 +31,7 @@
src="'/inline/story_detail_form.html'"
ng-show="showEditForm">
</div>
<hr/>
<div ng-include src="'/inline/task_list.html'"></div>
<hr/>
<div ng-include src="'/inline/tags.html'"></div>
@ -296,54 +297,379 @@
<i class="fa fa-plus"></i>
</span>
</h4>
</script>
<!-- Template for the task list -->
<script type="text/ng-template" id="/inline/task_list.html">
<table class="table table-striped table-supercondensed">
<thead>
<tr>
<td colspan="8"><strong>Tasks</strong></td>
</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="task in tasks | orderBy:'-status'"
ng-include
src="'/inline/task_list_item.html'">
</tr>
<tr ng-if="tasks.length == 0 && !showAddTaskForm">
<td colspan="8">
<p class="text-muted text-center">
<em>This story has no tasks.</em>
</p>
</td>
</tr>
<tr ng-if="showAddTaskForm"
ng-include
src="'/inline/task_edit_form.html'">
</tr>
<hr />
<tr>
<td colspan="8" class="text-left">
<button class="btn btn-default" type="button"
ng-click="showAddTaskForm = !showAddTaskForm"
ng-show="isLoggedIn">
<i class="fa fa-plus" ng-if="!showAddTaskForm"></i>
<i class="fa fa-minus" ng-if="showAddTaskForm"></i>
<strong> Add task </strong>
</button>
</td>
</tr>
</tbody>
</table>
<h3>Tasks</h3>
<div ng-repeat="name in projectNames">
<h4>
<i class="fa fa-sb-project text-muted"></i>
<a href="#!/project/{{ projects[name].id }}">{{ name }}</a>
</h4>
<div ng-repeat="branchName in projects[name].branchNames">
<div class="row" ng-if="branchName != 'master'">
<div class="col-xs-3">
<strong>
&emsp;&emsp;{{ branchName }}
</strong>
</div>
</div>
<div class="row" ng-if="branchName == 'master'">
<div class="col-xs-12" ng-include src="'/inline/task_table.html'"></div>
</div>
<div class="row" ng-if="branchName != 'master'">
<div class="col-xs-11 col-xs-offset-1"
ng-include src="'/inline/task_table.html'">
</div>
</div>
</div>
</div>
<div ng-show="newTask.show" ng-include src="'/inline/new_task.html'"></div>
<button class="btn btn-default"
ng-show="!newTask.show"
ng-click="newTask.show = !newTask.show">
<i class="fa fa-plus-circle"></i>
Affects other project
</button>
</script>
<!-- Template for the task list -->
<!-- Template for a table of tasks -->
<script type="text/ng-template" id="/inline/task_table.html">
<table class="table table-striped table-supercondensed">
<tr ng-repeat="task in projects[name].branches[branchName].tasks | orderBy: '-status'"
ng-include src="'/inline/task_list_item.html'">
</tr>
<tr ng-show="isLoggedIn && !projects[name].branches[branchName].showAddTask">
<td class="text-center">
<a href
ng-click="projects[name].branches[branchName].showAddTask =
!projects[name].branches[branchName].showAddTask">
<i class="fa fa-plus-circle"></i>
Add task affecting this project
</a>
</td>
</tr>
<tr ng-show="projects[name].branches[branchName].showAddTask"
ng-include src="'/inline/task_edit_form.html'">
</tr>
</table>
</script>
<!-- Template for an item in the task list -->
<script type="text/ng-template" id="/inline/task_list_item.html">
<td>
<div class="row">
<div class="col-xs-4 task-title">
<div>
<a href ng-click="showDetail = !showDetail">
<i class="fa fa-caret-down" ng-show="showDetail"></i>
<i class="fa fa-caret-right" ng-show="!showDetail"></i>
</a>
<strong>{{ task.id }}</strong>
&nbsp;
</div>
<div class="title">
<input-inline
ng-model="task.title"
enabled="isLoggedIn"
on-change="updateTask(task, 'title', task.title)"
empty-prompt="Click to set title."
empty-disabled-prompt="No title."
maxlength="255"
as-inline="true"
/>
</div>
</div>
<div class="col-xs-2">
<user-typeahead
ng-model="task.assignee_id"
enabled="isLoggedIn"
on-change="updateTask(task, 'assignee_id', task.assignee_id)"
empty-prompt="Click to assign."
empty-disabled-prompt="Not assigned."
as-inline="true"
/>
</div>
<div class="col-xs-2">
<task-status-dropdown
editable="{{isLoggedIn}}"
on-change="updateTask(task, 'status', status)"
status="{{ task.status }}"
/>
</div>
<div class="col-xs-2">
<task-priority-dropdown
editable="{{isLoggedIn}}"
on-change="updateTask(task, 'priority', priority)"
priority="{{newTask.priority}}"
/>
</div>
<!-- Review link should go here once implemented in the API -->
</div>
<div class="row button-row" ng-show="showDetail">
<div class="col-xs-1"></div>
<div class="col-xs-10">
<project-typeahead
auto-focus="false"
ng-model="task.project_id"
ng-show="changingProject"
enabled="isLoggedIn"
on-change="updateTask(task, 'project_id', task.project_id, name, branchName);
changingProject = false"
empty-prompt="Click to set a project"
empty-disabled-prompt="No project set."
as-inline="false"
placeholder="Enter project name">
</project-typeahead>
<button class="btn btn-xs btn-default"
ng-click="changingProject = !changingProject">
{{ changingProject ? 'Cancel' : 'Change project' }}
</button>
<button class="btn btn-xs btn-default"
ng-show="tasks.length > 1"
ng-click="removeTask(task, name, branchName)">
Delete
</button>
</div>
</div>
<div class="row" ng-show="showDetail">
<div class="col-xs-10 col-xs-offset-1">
<insert-markdown content="task.link" ng-show="!task.editing"></insert-markdown>
<insert-markdown content="task.tempNotes" ng-show="task.editing && notesPreview"></insert-markdown>
<form name="taskNotesForm" ng-show="task.editing">
<div class="form-group">
<textarea placeholder="Enter task notes here"
class="form-control context-edit"
msd-elastic
rows="3"
ng-show="isLoggedIn"
ng-disabled="isUpdating"
ng-model="task.tempNotes">
</textarea>
</div>
<div class="clearfix">
<button type="button" ng-show="isLoggedIn"
class="btn btn-default" ng-click="notesPreview = !notesPreview">
Toggle Preview
</button>
<div class="pull-right">
<div class="btn" ng-show="isUpdating">
<i class="fa fa-spinner fa-lg fa-spin"></i>
</div>
<button type="button" ng-show="isLoggedIn"
class="btn btn-primary"
ng-click="updateTask(task, 'link', task.tempNotes);
cancelEditNotes(task)"
ng-disabled="!taskNotesForm.$valid">
Save
</button>
<button type="button" ng-show="isLoggedIn"
class="btn btn-default"
ng-click="cancelEditNotes(task)">
Cancel
</button>
</div>
</div>
</form>
<div class="row text-center" ng-show="!task.editing && !task.link">
<button class="btn btn-primary btn-xs"
ng-click="editNotes(task)">
<i class="fa fa-pencil"></i> Add notes
</button>
</div>
</div>
<div class="col-xs-1" ng-show="!task.editing && task.link">
<button class="btn btn-primary btn-xs"
ng-click="editNotes(task)">
<i class="fa fa-pencil"></i> Edit
</button>
</div>
</div>
</td>
</script>
<!-- Template for the task add form. -->
<script type="text/ng-template" id="/inline/task_edit_form.html">
<td>
<div class="row">
<div class="col-xs-4 task-title">
<div>
<a href ng-click="showDetail = !showDetail">
<i class="fa fa-caret-down" ng-show="showDetail"></i>
<i class="fa fa-caret-right" ng-show="!showDetail"></i>
</a>
&nbsp;
</div>
<input-inline
auto-focus="true"
ng-model="projects[name].branches[branchName].newTask.title"
enabled="isLoggedIn"
on-change="updateTaskInline()"
empty-prompt="Click to assign."
empty-disabled-prompt="Not assigned."
maxlength="255"
as-inline="false"
placeholder="Enter task name"
/>
</div>
<div class="col-xs-2">
<user-typeahead
auto-focus="false"
ng-model="projects[name].branches[branchName].newTask.assignee_id"
enabled="isLoggedIn"
on-change="updateTaskInline()"
empty-prompt="Click to assign."
empty-disabled-prompt="Not assigned."
as-inline="false"
placeholder="Assign user to task"
/>
</div>
<div class="col-xs-2">
<task-status-dropdown
editable="{{isLoggedIn}}"
on-change="updateTask(projects[name].branches[branchName].newTask, 'status', status)"
status="{{projects[name].branches[branchName].newTask.status}}"
/>
</div>
<div class="col-xs-2">
<task-priority-dropdown
editable="{{isLoggedIn}}"
on-change="updateTask(projects[name].branches[branchName].newTask, 'priority', priority)"
priority="{{projects[name].branches[branchName].newTask.priority}}"
/>
</div>
<!-- Review link should go here once implemented in the API -->
<div class="col-xs-2 text-right">
<button ng-click="createTask(projects[name].branches[branchName].newTask,
projects[name].branches[branchName])"
class="btn btn-primary">
Save
</button>
<button ng-click="projects[name].branches[branchName].showAddTask =
!projects[name].branches[branchName].showAddTask"
class="btn btn-default">
Cancel
</button>
</div>
</div>
<div class="row" ng-show="showDetail">
<div class="col-xs-10 col-xs-offset-1">
<textarea ng-model="projects[name].branches[branchName].newTask.link"
class="form-control context-edit"
msd-elastic
rows="3"
ng-show="isLoggedIn"
placeholder="Task notes">
</textarea>
</div>
</div>
</td>
</script>
<!-- Template for creating a task in an as-yet unrelated project -->
<script type="text/ng-template" id="/inline/new_task.html">
<div>
<h4>
<i class="fa fa-sb-project text-muted"></i>
<project-typeahead
auto-focus="false"
ng-model="newTask.project_id"
enabled="isLoggedIn"
on-change="updateTaskInline()"
empty-prompt="Click to set a project"
empty-disabled-prompt="No project set."
as-inline="false"
placeholder="Enter project name">
</project-typeahead>
</h4>
<div class="row">
<div class="col-xs-12">
<table class="table table-supercondensed">
<tr>
<td>
<div class="row">
<div class="col-xs-4 task-title">
<div>
<a href ng-click="showDetail = !showDetail">
<i class="fa fa-caret-down" ng-show="showDetail"></i>
<i class="fa fa-caret-right" ng-show="!showDetail"></i>
</a>
&nbsp;
</div>
<input-inline
auto-focus="true"
ng-model="newTask.title"
enabled="isLoggedIn"
on-change="updateTaskInline()"
empty-prompt="Click to assign."
empty-disabled-prompt="Not assigned."
maxlength="255"
as-inline="false"
placeholder="Enter task name"
/>
</div>
<div class="col-xs-2">
<user-typeahead
auto-focus="false"
ng-model="newTask.assignee_id"
enabled="isLoggedIn"
on-change="updateTaskInline()"
empty-prompt="Click to assign."
empty-disabled-prompt="Not assigned."
as-inline="false"
placeholder="Assign user to task"
/>
</div>
<div class="col-xs-2">
<task-status-dropdown
editable="{{isLoggedIn}}"
on-change="updateTask(newTask, 'status', status)"
status="{{newTask.status}}"
/>
</div>
<!-- Review link should go here once implemented in the API -->
<div class="col-xs-2">
<task-priority-dropdown
editable="{{isLoggedIn}}"
on-change="updateTask(newTask, 'priority', priority)"
priority="{{newTask.priority}}"
/>
</div>
<div class="col-xs-2 text-right">
<button ng-click="createTask(newTask)"
class="btn btn-primary">
Save
</button>
<button ng-click="newTask.show = !newTask.show"
class="btn btn-default">
Cancel
</button>
</div>
</div>
<div class="row" ng-show="showDetail">
<div class="col-xs-10 col-xs-offset-1">
<textarea ng-model="newTask.link"
class="form-control context-edit"
msd-elastic
rows="3"
ng-show="isLoggedIn"
placeholder="Task notes">
</textarea>
</div>
</div>
</td>
</tr>
</table>
</div>
</div>
</div>
</script>
<!-- Template for the events stream -->
<script type="text/ng-template" id="/inline/discussion.html">
<div>
<div class="clearfix">
@ -429,135 +755,3 @@
<hr />
</div>
</script>
<!-- Template for an item in the task list -->
<script type="text/ng-template" id="/inline/task_list_item.html">
<td class="col-xs-1 center-vertical">{{task.id}}:</td>
<td class="col-xs-3 center-vertical">
<input-inline
ng-model="task.title"
enabled="isLoggedIn"
on-change="updateTask(task, 'title', task.title)"
empty-prompt="Click to assign."
empty-disabled-prompt="Not assigned."
maxlength="255"
as-inline="true"
/>
</td>
<td class="col-xs-1 center-vertical">
<button class="btn btn-xs btn-task-notes"
ng-class="{'btn-default': !task.link,
'btn-primary': task.link}"
ng-click="showTaskNotes(task)"
title="Task notes">
<i class="fa"
ng-class="{'fa-sticky-note-o': !task.link,
'fa-sticky-note': task.link}"></i>
</button>
</td>
<td class="col-xs-3 center-vertical">
<project-typeahead
ng-model="task.project_id"
enabled="isLoggedIn"
on-change="updateTask(task, 'project_id', task.project_id)"
empty-prompt="Click to assign."
empty-disabled-prompt="Not assigned."
as-inline="true"
/>
</td>
<td class="col-xs-2 center-vertical">
<user-typeahead
ng-model="task.assignee_id"
enabled="isLoggedIn"
on-change="updateTask(task, 'assignee_id', task.assignee_id)"
empty-prompt="Click to assign."
empty-disabled-prompt="Not assigned."
as-inline="true"
/>
</td>
<td class="text-center col-xs-1 center-vertical">
<task-priority-dropdown
editable="{{isLoggedIn}}"
on-change="updateTask(task, 'priority', priority)"
priority="{{task.priority}}"
/>
</td>
<td class="text-center col-xs-1 center-vertical">
<task-status-dropdown
editable="{{isLoggedIn}}"
on-change="updateTask(task, 'status', status)"
status="{{task.status}}"
/>
</td>
<td class="text-right col-xs-1 center-vertical">
<a ng-show="isLoggedIn"
ng-click="removeTask(task)">
<i class="fa fa-times fa-lg"></i>
</a>
</td>
</script>
<!-- Template for the task add form. -->
<script type="text/ng-template" id="/inline/task_edit_form.html">
<td class="col-xs-1"></td>
<td class="col-xs-3">
<input-inline
auto-focus="true"
ng-model="newTask.title"
enabled="isLoggedIn"
on-change="updateTaskInline()"
empty-prompt="Click to assign."
empty-disabled-prompt="Not assigned."
maxlength="255"
as-inline="false"
placeholder="Enter task name"
/>
</td>
<td class="col-xs-1">
</td>
<td class="col-xs-3">
<project-typeahead
auto-focus="false"
ng-model="newTask.project_id"
enabled="isLoggedIn"
on-change="updateTaskInline()"
empty-prompt="Click to assign."
empty-disabled-prompt="Not assigned."
as-inline="false"
placeholder="Enter project name"
/>
</td>
<td class="col-xs-2">
<user-typeahead
auto-focus="false"
ng-model="newTask.assignee_id"
enabled="isLoggedIn"
on-change="updateTaskInline()"
empty-prompt="Click to assign."
empty-disabled-prompt="Not assigned."
as-inline="false"
placeholder="Assign user to task"
/>
</td>
<td class="text-center col-xs-1">
<task-priority-dropdown
editable="{{isLoggedIn}}"
on-change="updateTask(newTask, 'priority', priority)"
priority="{{newTask.priority}}"
/>
</td>
<td class="text-center col-xs-1">
<task-status-dropdown
editable="{{isLoggedIn}}"
on-change="updateTask(newTask, 'status', status)"
status="{{newTask.status}}"
/>
</td>
<td class="text-right col-xs-1">
<button ng-click="createTask()"
class="btn btn-primary">
Save
</button>
</td>
</script>

View File

@ -1,68 +0,0 @@
<!--
~ Copyright (c) 2016 Codethink Limited
~
~ Licensed under the Apache License, Version 2.0 (the "License"); you may
~ not use this file except in compliance with the License. You may obtain
~ a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
~ WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
~ License for the specific language governing permissions and limitations
~ under the License.
-->
<div class="panel panel-default card-modal">
<div class="panel-heading clearfix">
<button type="button" class="close" aria-hidden="true"
ng-click="close()">&times;
</button>
<h3 class="panel-title">Notes on {{task.title}}</h3>
</div>
<div class="panel-body">
<div ng-show="!isLoggedIn || !editing || preview">
<insert-markdown content="task.link"></insert-markdown>
</div>
<button type="button" ng-show="isLoggedIn && !editing"
class="btn btn-primary pull-right"
ng-click="editing = !editing">
<i class="fa fa-pencil"></i> Edit
</button>
<form name="taskNotesForm" ng-show="editing">
<div class="form-group">
<textarea placeholder="Enter task notes here"
class="form-control context-edit"
msd-elastic
rows="3"
ng-show="isLoggedIn"
ng-disabled="isUpdating"
ng-model="task.link">
</textarea>
</div>
<div class="clearfix">
<button type="button" ng-show="isLoggedIn"
class="btn btn-default" ng-click="preview = !preview">
Toggle Preview
</button>
<div class="pull-right">
<div class="btn" ng-show="isUpdating">
<i class="fa fa-spinner fa-lg fa-spin"></i>
</div>
<button type="button" ng-show="isLoggedIn"
class="btn btn-primary"
ng-click="update()"
ng-disabled="!taskNotesForm.$valid">
Save
</button>
<button type="button" ng-show="isLoggedIn"
class="btn btn-default"
ng-click="cancel()">
Cancel
</button>
</div>
</div>
</form>
<div>
</div>

View File

@ -2,17 +2,19 @@
<div class="form-group"
ng-if="!enabled || !showForm">
<p class="form-control-static">
{{ inputText }}
&nbsp;
<a href=""
ng-focus="toggleForm()"
ng-click="toggleForm()"
ng-if="!showForm && enabled">
<span ng-if="inputText">
{{inputText}}
<i class="fa fa-edit"></i>
<i class="fa fa-pencil"></i>
</span>
<em ng-if="!inputText" class="text-muted">
{{emptyPrompt}}
<i class="fa fa-edit"></i>
<i class="fa fa-pencil"></i>
</em>
</a>

View File

@ -8,21 +8,19 @@
ng-if="project && !project.$resolved"></i>
&nbsp;
<a
href="#!/project/{{project.id}}">
{{project.name}}
</a>
<a href="#!/project/{{project.id}}">{{project.name}}</a>
&nbsp;
<a href=""
ng-focus="toggleForm()"
ng-click="toggleForm()"
ng-if="!showForm && enabled">
<span ng-if="project">
<i class="fa fa-edit"></i>
<i class="fa fa-pencil"></i>
</span>
<em ng-if="!project" class="text-muted">
{{emptyPrompt}}
<i class="fa fa-edit"></i>
<i class="fa fa-pencil"></i>
</em>
</a>

View File

@ -1,7 +1,7 @@
<span class="label label-{{style}}" ng-hide="editable">
{{priority | taskPriorityLabel}}
</span>
<div class="dropdown" ng-show="editable" dropdown>
<div class="dropdown form-control-static" ng-show="editable" dropdown>
<a class="btn btn-{{style}} btn-xs dropdown-toggle" dropdown-toggle>
{{priority | taskPriorityLabel}}
<i class="fa fa-caret-down"></i>

View File

@ -1,7 +1,7 @@
<span class="label label-{{style}}" ng-hide="editable">
{{statusName}}
</span>
<div class="dropdown" ng-show="editable" dropdown>
<div class="dropdown form-control-static" ng-show="editable" dropdown>
<a class="btn btn-{{style}} btn-xs dropdown-toggle" dropdown-toggle>
{{ statusName }}
<i class="fa fa-caret-down"></i>

View File

@ -8,17 +8,19 @@
ng-if="user && !user.$resolved"></i>
&nbsp;
<span ng-if="user && enabled">{{user.full_name}}</span>
&nbsp;
<a href=""
ng-focus="toggleForm()"
ng-click="toggleForm()"
ng-if="!showForm && enabled">
<span ng-if="user">
{{user.full_name}}
<i class="fa fa-edit"></i>
<i class="fa fa-pencil"></i>
</span>
<em ng-if="!user" class="text-muted">
{{emptyPrompt}}
<i class="fa fa-edit"></i>
<i class="fa fa-pencil"></i>
</em>
</a>

View File

@ -226,7 +226,3 @@ div .container-fluid {
.modal-checkbox {
margin-left: 0px !important;
}
.btn-task-notes i {
color: @black !important;
}

View File

@ -11,3 +11,38 @@
left: 150px;
box-sizing: border-box;
}
.task-title {
& > div {
vertical-align: top;
display: inline-block;
padding-top: 7px;
padding-bottom: 7px;
}
& .title {
max-width: 75%;
}
& .form-control-static {
padding-top: 0;
padding-bottom: 0;
}
}
input-inline, project-typeahead, user-typeahead, task-status-dropdown {
display: inline-block;
& .form-group {
margin-bottom: 0;
}
}
.noselect {
user-select: none;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
}