Merge branch '74-students-add-new-task' into 'dev'

Resolve "Добавление новой задачи"

Closes #78 and #74

See merge request romanov73/ng-tracker!47
This commit is contained in:
Anton Romanov 2019-04-16 09:36:58 +00:00
commit 3facc0c26e
21 changed files with 1630 additions and 941 deletions

View File

@ -0,0 +1,16 @@
package ru.ulstu.students.controller;
import org.springframework.validation.Errors;
public class Navigation {
public static final String REDIRECT_TO = "redirect:%s";
public static final String TASKS_PAGE = "/students/tasks";
public static final String TASK_PAGE = "/students/task";
public static String hasErrors(Errors errors, String page) {
if (errors.hasErrors()) {
return page;
}
return null;
}
}

View File

@ -0,0 +1,84 @@
package ru.ulstu.students.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.*;
import ru.ulstu.deadline.model.Deadline;
import ru.ulstu.students.model.Task;
import ru.ulstu.students.model.TaskDto;
import ru.ulstu.students.service.TaskService;
import springfox.documentation.annotations.ApiIgnore;
import javax.validation.Valid;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;
import static org.springframework.util.StringUtils.isEmpty;
import static ru.ulstu.students.controller.Navigation.*;
@Controller()
@RequestMapping(value = "/students")
@ApiIgnore
public class TaskController {
private final TaskService taskService;
public TaskController(TaskService taskService) {
this.taskService = taskService;
}
@GetMapping("/tasks")
public void getTasks(ModelMap modelMap) {
modelMap.put("tasks", taskService.findAllDto());
}
@GetMapping("/dashboard")
public void getDashboard(ModelMap modelMap) {
modelMap.put("tasks", taskService.findAllDto());
}
@GetMapping("/task")
public void getTask(ModelMap modelMap, @RequestParam(value = "id") Integer id) {
if (id != null && id > 0) {
modelMap.put("taskDto", taskService.findOneDto(id));
} else {
modelMap.put("taskDto", new TaskDto());
}
}
@PostMapping(value = "/task", params = "save")
public String save(@Valid TaskDto taskDto, Errors errors) throws IOException {
filterEmptyDeadlines(taskDto);
if (taskDto.getDeadlines().isEmpty()) {
errors.rejectValue("deadlines", "errorCode", "Не может быть пустым");
}
if (errors.hasErrors()) {
return TASK_PAGE;
}
taskService.save(taskDto);
return String.format(REDIRECT_TO, TASKS_PAGE);
}
@PostMapping(value = "/task", params = "addDeadline")
public String addDeadline(@Valid TaskDto taskDto, Errors errors) {
filterEmptyDeadlines(taskDto);
if (errors.hasErrors()) {
return TASK_PAGE;
}
taskDto.getDeadlines().add(new Deadline());
return TASK_PAGE;
}
@ModelAttribute("allStatuses")
public List<Task.TaskStatus> getTaskStatuses() {
return taskService.getTaskStatuses();
}
private void filterEmptyDeadlines(TaskDto taskDto) {
taskDto.setDeadlines(taskDto.getDeadlines().stream()
.filter(dto -> dto.getDate() != null || !isEmpty(dto.getDescription()))
.collect(Collectors.toList()));
}
}

View File

@ -0,0 +1,118 @@
package ru.ulstu.students.model;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.hibernate.validator.constraints.NotBlank;
import ru.ulstu.core.model.BaseEntity;
import ru.ulstu.deadline.model.Deadline;
import ru.ulstu.tags.model.Tag;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Entity
public class Task extends BaseEntity {
public enum TaskStatus {
IN_WORK("В работе"),
COMPLETED("Завершен"),
FAILED("Провалены сроки"),
LOADED_FROM_KIAS("Загружен автоматически");
private String statusName;
TaskStatus(String name) {
this.statusName = name;
}
public String getStatusName() {
return statusName;
}
}
@NotBlank
private String title;
private String description;
@Enumerated(value = EnumType.STRING)
private ru.ulstu.students.model.Task.TaskStatus status = TaskStatus.IN_WORK;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name = "task_id", unique = true)
@Fetch(FetchMode.SUBSELECT)
@OrderBy("date")
private List<Deadline> deadlines = new ArrayList<>();
@Column(name = "create_date")
@Temporal(TemporalType.TIMESTAMP)
private Date createDate = new Date();
@Column(name = "update_date")
@Temporal(TemporalType.TIMESTAMP)
private Date updateDate = new Date();
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "task_tags",
joinColumns = {@JoinColumn(name = "task_id")},
inverseJoinColumns = {@JoinColumn(name = "tag_id")})
private List<Tag> tags = new ArrayList<>();
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public TaskStatus getStatus() {
return status;
}
public void setStatus(TaskStatus status) {
this.status = status;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public List<Deadline> getDeadlines() {
return deadlines;
}
public void setDeadlines(List<Deadline> deadlines) {
this.deadlines = deadlines;
}
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
public Date getUpdateDate() {
return updateDate;
}
public void setUpdateDate(Date updateDate) {
this.updateDate = updateDate;
}
public List<Tag> getTags() {
return tags;
}
public void setTags(List<Tag> tags) {
this.tags = tags;
}
}

View File

@ -0,0 +1,144 @@
package ru.ulstu.students.model;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.validator.constraints.NotEmpty;
import ru.ulstu.deadline.model.Deadline;
import ru.ulstu.tags.model.Tag;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
public class TaskDto {
private final static int MAX_TAGS_LENGTH = 50;
private Integer id;
@NotEmpty
private String title;
private String description;
private Task.TaskStatus status;
private List<Deadline> deadlines = new ArrayList<>();
private Date createDate;
private Date updateDate;
private Set<Integer> tagIds;
private List<Tag> tags;
public TaskDto() {
deadlines.add(new Deadline());
}
@JsonCreator
public TaskDto(@JsonProperty("id") Integer id,
@JsonProperty("title") String title,
@JsonProperty("description") String description,
@JsonProperty("createDate") Date createDate,
@JsonProperty("updateDate") Date updateDate,
@JsonProperty("status") Task.TaskStatus status,
@JsonProperty("deadlines") List<Deadline> deadlines,
@JsonProperty("tagIds") Set<Integer> tagIds,
@JsonProperty("tags") List<Tag> tags) {
this.id = id;
this.title = title;
this.status = status;
this.deadlines = deadlines;
this.createDate = createDate;
this.updateDate = updateDate;
this.description = description;
this.tags = tags;
}
public TaskDto(Task task) {
this.id = task.getId();
this.title = task.getTitle();
this.status = task.getStatus();
this.deadlines = task.getDeadlines();
this.createDate = task.getCreateDate();
this.updateDate = task.getUpdateDate();
this.description = task.getDescription();
this.tags = task.getTags();
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Task.TaskStatus getStatus() {
return status;
}
public void setStatus(Task.TaskStatus status) {
this.status = status;
}
public List<Deadline> getDeadlines() {
return deadlines;
}
public void setDeadlines(List<Deadline> deadlines) {
this.deadlines = deadlines;
}
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
public Date getUpdateDate() {
return updateDate;
}
public void setUpdateDate(Date updateDate) {
this.updateDate = updateDate;
}
public Set<Integer> getTagIds() {
return tagIds;
}
public void setTagIds(Set<Integer> tagIds) {
this.tagIds = tagIds;
}
public List<Tag> getTags() {
return tags;
}
public void setTags(List<Tag> tags) {
this.tags = tags;
}
public String getTagsString() {
return StringUtils.abbreviate(tags
.stream()
.map(tag -> tag.getTagName())
.collect(Collectors.joining(", ")), MAX_TAGS_LENGTH);
}
}

View File

@ -0,0 +1,7 @@
package ru.ulstu.students.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import ru.ulstu.students.model.Task;
public interface TaskRepository extends JpaRepository<Task, Integer> {
}

View File

@ -0,0 +1,95 @@
package ru.ulstu.students.service;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import ru.ulstu.deadline.service.DeadlineService;
import ru.ulstu.students.model.Task;
import ru.ulstu.students.model.TaskDto;
import ru.ulstu.students.repository.TaskRepository;
import ru.ulstu.tags.service.TagService;
import java.io.IOException;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import static org.springframework.util.ObjectUtils.isEmpty;
import static ru.ulstu.core.util.StreamApiUtils.convert;
import static ru.ulstu.students.model.Task.TaskStatus.IN_WORK;
@Service
public class TaskService {
private final static int MAX_DISPLAY_SIZE = 40;
private final TaskRepository taskRepository;
private final DeadlineService deadlineService;
private final TagService tagService;
public TaskService(TaskRepository grantRepository,
DeadlineService deadlineService, TagService tagService) {
this.taskRepository = grantRepository;
this.deadlineService = deadlineService;
this.tagService = tagService;
}
public List<Task> findAll() {
return taskRepository.findAll();
}
public List<TaskDto> findAllDto() {
List<TaskDto> tasks = convert(findAll(), TaskDto::new);
tasks.forEach(taskDto -> taskDto.setTitle(StringUtils.abbreviate(taskDto.getTitle(), MAX_DISPLAY_SIZE)));
return tasks;
}
public TaskDto findOneDto(Integer id) {
return new TaskDto(taskRepository.findOne(id));
}
@Transactional
public Integer create(TaskDto taskDto) throws IOException {
Task newTask = copyFromDto(new Task(), taskDto);
newTask = taskRepository.save(newTask);
return newTask.getId();
}
private Task copyFromDto(Task task, TaskDto taskDto) throws IOException {
task.setTitle(taskDto.getTitle());
task.setDescription(taskDto.getDescription());
task.setStatus(taskDto.getStatus() == null ? IN_WORK : taskDto.getStatus());
task.setDeadlines(deadlineService.saveOrCreate(taskDto.getDeadlines()));
task.setCreateDate(task.getCreateDate() == null ? new Date() : task.getCreateDate());
task.setUpdateDate(new Date());
task.getTags().clear();
task.setTags(tagService.saveOrCreate(taskDto.getTags()));
return task;
}
@Transactional
public Integer update(TaskDto taskDto) throws IOException {
Task task = taskRepository.findOne(taskDto.getId());
taskRepository.save(copyFromDto(task, taskDto));
return task.getId();
}
@Transactional
public void delete(Integer taskId) throws IOException {
Task task = taskRepository.findOne(taskId);
taskRepository.delete(task);
}
public void save(TaskDto taskDto) throws IOException {
if (isEmpty(taskDto.getId())) {
create(taskDto);
} else {
update(taskDto);
}
}
public List<Task.TaskStatus> getTaskStatuses() {
return Arrays.asList(Task.TaskStatus.values());
}
}

View File

@ -0,0 +1,44 @@
package ru.ulstu.tags.model;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.hibernate.validator.constraints.NotEmpty;
import ru.ulstu.core.model.BaseEntity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.validation.constraints.Size;
@Entity
@Table(name = "tag")
public class Tag extends BaseEntity {
@NotEmpty
@Size(max = 50)
@Column(name = "tag_name")
private String tagName;
public Tag() {
}
@JsonCreator
public Tag(@JsonProperty("id") Integer id,
@JsonProperty("tag_name") String tagName) {
this.setId(id);
this.tagName = tagName;
}
public Tag(String name) {
this.tagName = name;
}
public String getTagName() {
return tagName;
}
public void setTagName(String tagName) {
this.tagName = tagName;
}
}

View File

@ -0,0 +1,12 @@
package ru.ulstu.tags.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import ru.ulstu.tags.model.Tag;
public interface TagRepository extends JpaRepository<Tag, Integer> {
@Query("SELECT t FROM Tag t WHERE (t.tagName = :tagName)")
Tag findByName(@Param("tagName") String tagName);
}

View File

@ -0,0 +1,53 @@
package ru.ulstu.tags.service;
import org.springframework.stereotype.Service;
import ru.ulstu.tags.model.Tag;
import ru.ulstu.tags.repository.TagRepository;
import javax.transaction.Transactional;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class TagService {
private final TagRepository tagRepository;
public TagService(TagRepository tagRepository) {
this.tagRepository = tagRepository;
}
public List<Tag> saveOrCreate(List<Tag> tags) {
return tags
.stream()
.map(tag -> {
if (tag.getId() != null) {
return getExistById(tag);
} else {
Tag existTag = isExistByName(tag.getTagName());
return existTag != null ? existTag : create(tag);
}
}).collect(Collectors.toList());
}
@Transactional
public Tag getExistById(Tag tag) {
return tagRepository.findOne(tag.getId());
}
@Transactional
public Tag isExistByName(String tagName) {
return tagRepository.findByName(tagName);
}
@Transactional
public Tag create(Tag tag) {
Tag newTag = new Tag();
newTag.setTagName(tag.getTagName());
newTag = tagRepository.save(newTag);
return newTag;
}
}

View File

@ -0,0 +1,17 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
<changeSet author="nastya" id="20190410_000000-1">
<addColumn tableName="tag">
<column name="version" type="integer"/>
</addColumn>
<renameColumn tableName="tag" oldColumnName="tagname" newColumnName="tag_name"/>
</changeSet>
<changeSet author="nastya" id="20190410_000000-2">
<addColumn tableName="task">
<column name="version" type="integer"/>
</addColumn>
</changeSet>
</databaseChangeLog>

View File

@ -23,5 +23,6 @@
<include file="db/changelog-20190327_000000-schema.xml"/> <include file="db/changelog-20190327_000000-schema.xml"/>
<include file="db/changelog-20190331_000000-schema.xml"/> <include file="db/changelog-20190331_000000-schema.xml"/>
<include file="db/changelog-20190331_000010-schema.xml"/> <include file="db/changelog-20190331_000010-schema.xml"/>
<include file="db/changelog-20190410_000000-schema.xml"/>
<include file="db/common/changelog-20190312_130000-schema.xml"/> <include file="db/common/changelog-20190312_130000-schema.xml"/>
</databaseChangeLog> </databaseChangeLog>

View File

@ -777,25 +777,11 @@ ul.social-buttons li a:active, ul.social-buttons li a:focus, ul.social-buttons l
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.05); box-shadow: 0 5px 20px rgba(0, 0, 0, 0.05);
} }
@media (min-width: 1500px) {
.col-xl-3 {
max-width: 20%;
}
.container {
max-width: 1340px;
}
}
.toolbar-button { .toolbar-button {
width: 100%; width: 100%;
margin: 5px; margin: 5px;
} }
.img-fluid {
width: 100% !important;
}
/* --------------------------------------------------- /* ---------------------------------------------------
FEEDBACK STYLE FEEDBACK STYLE
----------------------------------------------------- */ ----------------------------------------------------- */

View File

@ -1,24 +1,65 @@
.bootstrap-tagsinput{ .tags-container {
width: 100%; width: 100%;
padding: .375rem .75rem; padding: .375rem .75rem;
background-color: #fff;
border: 1px solid #ccc;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
display: inline-block;
color: #555;
vertical-align: middle;
border-radius: 4px;
max-width: 100%;
line-height: 22px;
cursor: text;
} }
.bootstrap-tagsinput .label{ .input-tag-name {
border: none;
box-shadow: none;
outline: none;
background-color: transparent;
padding: 0 6px;
margin: 0;
width: auto;
max-width: inherit;
}
display: inline; .tag {
display: inline-block;
padding: .2em .6em .3em; padding: .2em .6em .3em;
background-color: orange;
border-radius: .25em;
margin-right: 4px;
margin-bottom: 4px;
font-size: 75%; font-size: 75%;
font-weight: 700; font-weight: 700;
line-height: 2.5; line-height: 1.5;
color: #fff;
}
.tag-name span[data-role="remove"] {
margin-left: 8px;
cursor: pointer;
}
.tag-name span[data-role="remove"]:after {
content: "x";
padding: 0px 2px;
}
.tag-name input[type="text"] {
background: transparent;
border: none;
display: inline-flex;
font-size: 100%;
font-weight: 700;
line-height: 1.5;
color: #fff; color: #fff;
text-align: center; text-align: center;
white-space: nowrap; white-space: nowrap;
vertical-align: baseline; vertical-align: baseline;
border-radius: .25em; outline: none;
} cursor: default;
.bootstrap-tagsinput .label-info{
background-color: orange;
} }

View File

@ -1,5 +1,75 @@
/*<![CDATA[*/ /*<![CDATA[*/
$(document).ready(function () { $(document).ready(function () {
$("#tags .tag .tag-name input[type=text]").each(function() {
$(this).attr("size", $(this).val().length)
});
$("#task-form").keydown(function(event){
if(event.keyCode == 13) {
event.preventDefault();
return false;
}
});
function removeTag () {
$(this).parent().parent().remove();
}
$("#input-tag").keyup(function (event) {
if(event.keyCode == 13 || event.keyCode == 188) {
var tagNumber = $("#tags .tag").length;
var tagName = $.trim($(this).val());
var addTag = true;
// проверка, добавлен ли этот тег
$("#tags .tag .tag-name input[type=text]").each(function() {
if(tagName === $(this).val()) {
addTag = false;
return;
}
});
// если тег не добавлен
if(addTag) {
// контейнер тега
var newTagRow = $("<div/>")
.attr("id", 'tags' + tagNumber)
.addClass("tag");
// контейнер id
var idInput = $("<input/>")
.attr("type", "hidden")
.attr("id", "tags" + tagNumber + ".id")
.attr("name", "tags[" + tagNumber + "].id")
.attr("value", '');
// контейнер текста
var conDiv = $("<div/>")
.addClass("tag-name");
// текст тега
var nameInput = $("<input/>")
.attr("type", "text")
.attr("id", "tags" + tagNumber + ".tagName")
.attr("name", "tags[" + tagNumber + "].tagName")
.attr("value", tagName)
.attr("readonly", "true")
.attr("size", tagName.length);
// кнопка удалить тег
var removeSpan = $("<span/>")
.attr("data-role", "remove")
.bind("click", removeTag);
conDiv.append(nameInput);
conDiv.append(removeSpan);
newTagRow.append(idInput);
newTagRow.append(conDiv);
$(this).before(newTagRow);
}
$(this).val('');
}
});
$("span[data-role=remove]").click(removeTag);
$(".task-row").mouseenter(function (event) { $(".task-row").mouseenter(function (event) {
var taskRow = $(event.target).closest(".task-row"); var taskRow = $(event.target).closest(".task-row");
$(taskRow).css("background-color", "#f8f9fa"); $(taskRow).css("background-color", "#f8f9fa");

View File

@ -10,12 +10,6 @@
<!-- Portfolio Grid --> <!-- Portfolio Grid -->
<section class="bg-light" id="portfolio"> <section class="bg-light" id="portfolio">
<div class="container"> <div class="container">
<div class="row">
<div class="col-lg-12 text-center">
<h2 class="section-heading text-uppercase">Work hard</h2>
<h3 class="section-subheading text-muted">sometimes</h3>
</div>
</div>
<div class="row"> <div class="row">
<div class="col-md-4 col-sm-6 portfolio-item"> <div class="col-md-4 col-sm-6 portfolio-item">
<a class="portfolio-link" href="./papers/papers"> <a class="portfolio-link" href="./papers/papers">

View File

@ -7,14 +7,14 @@
<div th:fragment="taskDashboard (task)" class="col-12 col-sm-12 col-md-12 col-lg-4 col-xl-3 dashboard-card"> <div th:fragment="taskDashboard (task)" class="col-12 col-sm-12 col-md-12 col-lg-4 col-xl-3 dashboard-card">
<div class="row"> <div class="row">
<div class="col-2"> <div class="col-2">
<!--<span th:replace="students/fragments/taskStatusFragment :: taskStatus(taskStatus=${task.status})"/>--> <span th:replace="students/fragments/taskStatusFragment :: taskStatus(taskStatus=${task.status})"/>
<span th:replace="students/fragments/taskStatusFragment"/> <!--<span th:replace="students/fragments/taskStatusFragment"/>-->
</div> </div>
<div class="col col-10 text-right"> <div class="col col-10 text-right">
<!--<h7 class="service-heading" th:text="${task.title}"> title</h7>--> <h7 class="service-heading" th:text="${task.title}"> title</h7>
<!--<p class="text-muted" th:text="${task.typeString}">authors</p>--> <p class="text-muted" th:text="${task.status.statusName}"> status</p>
<h7 class="service-heading" th:text="Title"> title</h7> <!--<h7 class="service-heading" th:text="Title"> title</h7>-->
<p class="text-muted" th:text="Type">type</p> <!--<p class="text-muted" th:text="Type">type</p>-->
</div> </div>
</div> </div>
</div> </div>

View File

@ -4,15 +4,15 @@
<meta charset="UTF-8"/> <meta charset="UTF-8"/>
</head> </head>
<body> <body>
<div class="row text-left task-row" style="background-color: white;"> <div th:fragment="taskLine (task)" class="row text-left task-row" style="background-color: white;">
<div class="col"> <div class="col">
<span th:replace="students/fragments/taskStatusFragment"/> <span th:replace="students/fragments/taskStatusFragment :: taskStatus(taskStatus=${task.status})"/>
<a th:href="@{'task?id='+ 1}"> <a th:href="@{'task?id='+${task.id}}">
<span class="h6" >Первая хадач</span> <span class="h6" th:text="${task.title}"></span>
<span class="text-muted">Курсовая работа</span> <span class="text-muted" th:text="${task.tagsString}"/>
</a> </a>
<input class="id-class" type="hidden" th:value="1" /> <input class="id-class" type="hidden" th:value="${task.id}"/>
<a class="remove-task pull-right d-none" th:href="@{'/students/delete/'+1}" <a class="remove-task pull-right d-none" th:href="@{'/students/delete/'+${task.id}}"
data-confirm="Удалить задачу?"> data-confirm="Удалить задачу?">
<i class="fa fa-trash" aria-hidden="true"></i> <i class="fa fa-trash" aria-hidden="true"></i>
</a> </a>

View File

@ -15,7 +15,7 @@
</div> </div>
<div class="col-12 col-sm-12 col-md-12 col-lg-4 col-xl-3"> <div class="col-12 col-sm-12 col-md-12 col-lg-4 col-xl-3">
<a href="./task" class="btn btn-light toolbar-button"><i class="fa fa-plus-circle" <a href="./task?id=0" class="btn btn-light toolbar-button"><i class="fa fa-plus-circle"
aria-hidden="true"></i> aria-hidden="true"></i>
Добавить задачу</a> Добавить задачу</a>

View File

@ -5,18 +5,14 @@
</head> </head>
<body> <body>
<span th:fragment="taskStatus (taskStatus)" class="fa-stack fa-1x"> <span th:fragment="taskStatus (taskStatus)" class="fa-stack fa-1x">
<!--<th:block th:switch="${taskStatus.name()}">--> <th:block th:switch="${taskStatus.name()}">
<th:block th:switch="'ON_PREPARATION'"> <!--<div th:case="'ATTENTION'">-->
<div th:case="'ATTENTION'"> <!--<i class="fa fa-circle fa-stack-2x text-warning"></i>-->
<i class="fa fa-circle fa-stack-2x text-warning"></i> <!--</div>-->
</div> <div th:case="'IN_WORK'">
<div th:case="'DRAFT'">
<i class="fa fa-circle fa-stack-2x text-draft"></i>
</div>
<div th:case="'ON_PREPARATION'">
<i class="fa fa-circle fa-stack-2x text-primary"></i> <i class="fa fa-circle fa-stack-2x text-primary"></i>
</div> </div>
<div th:case="'ON_REVIEW'"> <div th:case="'LOADED_FROM_KIAS'">
<i class="fa fa-circle fa-stack-2x text-review"></i> <i class="fa fa-circle fa-stack-2x text-review"></i>
</div> </div>
<div th:case="'COMPLETED'"> <div th:case="'COMPLETED'">
@ -25,12 +21,6 @@
<div th:case="'FAILED'"> <div th:case="'FAILED'">
<i class="fa fa-circle fa-stack-2x text-failed"></i> <i class="fa fa-circle fa-stack-2x text-failed"></i>
</div> </div>
<div th:case="'ACCEPTED'">
<i class="fa fa-circle fa-stack-2x text-accepted"></i>
</div>
<div th:case="'NOT_ACCEPTED'">
<i class="fa fa-circle fa-stack-2x text-not-accepted"></i>
</div>
</th:block> </th:block>
<i class="fa fa-check fa-stack-1x fa-inverse"></i> <i class="fa fa-check fa-stack-1x fa-inverse"></i>
</span> </span>

View File

@ -3,7 +3,8 @@
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorator="default" xmlns:th="http://www.w3.org/1999/xhtml" xmlns="http://www.w3.org/1999/html"> layout:decorator="default" xmlns:th="http://www.w3.org/1999/xhtml" xmlns="http://www.w3.org/1999/html">
<head> <head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-tagsinput/0.8.0/bootstrap-tagsinput.css"/> <link rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-tagsinput/0.8.0/bootstrap-tagsinput.css"/>
<link rel="stylesheet" href="../css/tasks.css"/> <link rel="stylesheet" href="../css/tasks.css"/>
</head> </head>
<body> <body>
@ -11,6 +12,7 @@
<div class="container" layout:fragment="content"> <div class="container" layout:fragment="content">
<section id="paper"> <section id="paper">
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-tagsinput/0.8.0/bootstrap-tagsinput.min.js"></script>
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col-lg-12 text-center"> <div class="col-lg-12 text-center">
@ -21,50 +23,76 @@
<hr/> <hr/>
<div class="row"> <div class="row">
<div class="col-lg-12"> <div class="col-lg-12">
<form id="task-form" method="post"> <form id="task-form" method="post" th:action="@{'/students/task?id='+ *{id == null ? '' : id} + ''}"
th:object="${taskDto}">
<div class="row"> <div class="row">
<div class="col-md-7 col-sm-12"> <div class="col-md-7 col-sm-12">
<input type="hidden" name="id"/> <input type="hidden" name="id" th:field="*{id}"/>
<div class="form-group"> <div class="form-group">
<label for="title">Название:</label> <label for="title">Название:</label>
<input class="form-control" id="title" type="text" placeholder="Название задачи"/> <input class="form-control" id="title" type="text" placeholder="Название задачи"
th:field="*{title}"/>
<p th:if="${#fields.hasErrors('title')}" th:errors="*{title}"
class="alert alert-danger">Incorrect title</p>
<p class="help-block text-danger"></p> <p class="help-block text-danger"></p>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="status">Статус:</label> <label for="status">Статус:</label>
<select class="form-control" id="status"> <select class="form-control" id="status" th:field="*{status}">
<option>Status</option> <option th:each="status : ${allStatuses}" th:value="${status}"
th:text="${status.statusName}">Status
</option>
</select> </select>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="comment">Описание задачи:</label> <label for="comment">Описание задачи:</label>
<textarea class="form-control" rows="3" id="comment"></textarea> <textarea class="form-control" rows="3" id="comment"
th:field="*{description}"></textarea>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="tags">Теги:</label> <label for="tags">Теги:</label>
<input class="form-control" data-role="tagsinput" placeholder="Теги задачи" id="tags"/> <div class="tags-container" id="tags">
<div class="tag" th:each="tag, rowStat : *{tags}">
<input type="hidden" th:field="*{tags[__${rowStat.index}__].id}"/>
<div class="tag-name">
<input type="text" readonly="true"
th:field="*{tags[__${rowStat.index}__].tagName}"/>
<span data-role="remove"></span>
</div>
</div>
<input class="input-tag-name" type="text" placeholder="Теги задачи"
id="input-tag"/>
</div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label>Дедлайны задачи:</label> <label>Дедлайны задачи:</label>
<div class="row"> <div class="row" th:each="deadline, rowStat : *{deadlines}">
<input type="hidden" /> <input type="hidden" th:field="*{deadlines[__${rowStat.index}__].id}"/>
<div class="col-6"> <div class="col-6">
<input type="date" class="form-control" name="deadline"/> <input type="date" class="form-control" name="deadline"
th:field="*{deadlines[__${rowStat.index}__].date}"/>
</div> </div>
<div class="col-4"> <div class="col-4">
<input class="form-control" type="text" placeholder="Описание"/> <input class="form-control" type="text" placeholder="Описание"
th:field="*{deadlines[__${rowStat.index}__].description}"/>
</div> </div>
<div class="col-2"> <div class="col-2">
<a class="btn btn-danger float-right"><span <a class="btn btn-danger float-right"
th:onclick="|$('#deadlines${rowStat.index}\\.description').val('');
$('#deadlines${rowStat.index}\\.date').val('');
$('#addDeadline').click();|"><span
aria-hidden="true"><i class="fa fa-times"/></span> aria-hidden="true"><i class="fa fa-times"/></span>
</a> </a>
</div> </div>
</div> </div>
<p th:if="${#fields.hasErrors('deadlines')}" th:errors="*{deadlines}"
class="alert alert-danger">Incorrect title</p>
</div> </div>
<div class="form-group"> <div class="form-group">
<input type="submit" id="addDeadline" name="addDeadline" class="btn btn-primary" value="Добавить <input type="submit" id="addDeadline" name="addDeadline" class="btn btn-primary"
value="Добавить
дедлайн"/> дедлайн"/>
</div> </div>
<div class="clearfix"></div> <div class="clearfix"></div>
@ -73,9 +101,9 @@
type="submit"> type="submit">
Сохранить Сохранить
</button> </button>
<button id="cancelButton" class="btn btn-default text-uppercase" href="/students/tasks"> <a id="cancelButton" class="btn btn-default text-uppercase" href="/students/tasks">
Отмена Отмена
</button> </a>
</div> </div>
</div> </div>
<div class="col-md-4 offset-md-1 col-sm-12 offset-sm-0"> <div class="col-md-4 offset-md-1 col-sm-12 offset-sm-0">
@ -85,8 +113,8 @@
<h6 class="my-0">Дата создания:</h6> <h6 class="my-0">Дата создания:</h6>
</div> </div>
<div class="col"> <div class="col">
<small class="text-muted"> <small class="text-muted"
<!--th:text="${taskDto.createDate == null ? '' : #dates.format(taskDto.createDate, 'dd.MM.yyyy HH:mm')}">--> th:text="${taskDto.createDate == null ? '' : #dates.format(taskDto.createDate, 'dd.MM.yyyy HH:mm')}">
text text
</small> </small>
</div> </div>
@ -98,8 +126,8 @@
<h6 class="my-0">Дата изменения:</h6> <h6 class="my-0">Дата изменения:</h6>
</div> </div>
<div class="col"> <div class="col">
<small class="text-muted"> <small class="text-muted"
<!--th:text="${paperDto.updateDate == null ? '' : #dates.format(paperDto.updateDate, 'dd.MM.yyyy HH:mm')}">--> th:text="${taskDto.updateDate == null ? '' : #dates.format(taskDto.updateDate, 'dd.MM.yyyy HH:mm')}">
text text
</small> </small>
</div> </div>
@ -111,8 +139,8 @@
</div> </div>
</div> </div>
</div> </div>
<script src="/js/tasks.js"></script>
</section> </section>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-tagsinput/0.8.0/bootstrap-tagsinput.min.js"></script>
</div> </div>
</body> </body>
</html> </html>

View File

@ -20,8 +20,8 @@
<hr/> <hr/>
<div class="row"> <div class="row">
<div class="col-md-9 col-sm-12"> <div class="col-md-9 col-sm-12">
<th:block> <th:block th:each="task : ${tasks}">
<div th:replace="students/fragments/taskLineFragment"/> <div th:replace="students/fragments/taskLineFragment :: taskLine(task=${task})"/>
</th:block> </th:block>
</div> </div>
<div class="col-md-3 col-sm-12"> <div class="col-md-3 col-sm-12">
@ -37,21 +37,10 @@
<select class="form-control" id="tags" <select class="form-control" id="tags"
onchange="this.form.submit();"> onchange="this.form.submit();">
<option value="">Все типы</option> <option value="">Все типы</option>
<option value="">Все типы</option>
<option value="">Все типы</option>
<option value="">Все типы</option>
<option value="">Все типы</option>
<option value="">Все типы</option>
<option value="">Все типы</option>
<option value="">Все типы</option>
<option value="">Все типы</option>
<option value="">Все типы</option>
<option value="">Все типы</option>
<!--<option th:each="year: ${allYears}" th:value="${year}"--> <!--<option th:each="year: ${allYears}" th:value="${year}"-->
<!--th:text="${year}">year--> <!--th:text="${year}">year-->
<!--</option>--> <!--</option>-->
</select> </select>
</div> </div>
</div> </div>
</div> </div>