Skip to content

Commit 77475a1

Browse files
committed
add card cover image and activity detail
1 parent 044661e commit 77475a1

File tree

7 files changed

+99
-13
lines changed

7 files changed

+99
-13
lines changed

front-end/src/modals/CardModal.vue

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@
7474
<div class="wrapper-body">
7575
<div class="activity" v-for="activity in cardActivities" v-bind:key="activity.id">
7676
<div><strong>{{ activity.user.name }}</strong> <span class="when">{{ activity.when }} ago</span></div>
77-
<div class="detail">{{ activity.detail.comment }}</div>
77+
<div class="detail" :class="activity.type">{{ activity.actionDetail }}</div>
7878
</div>
7979
</div>
8080
</div>
@@ -152,9 +152,23 @@ export default {
152152
const now = new Date()
153153
this.activities.forEach(activity => {
154154
const detail = JSON.parse(activity.detail)
155+
let actionDetail = ''
156+
if (activity.type === 'add-comment') {
157+
actionDetail = detail.comment
158+
} else if (activity.type === 'add-card') {
159+
actionDetail = 'Added this card'
160+
} else if (activity.type === 'add-attachment') {
161+
actionDetail = 'Added attachment ' + detail.fileName
162+
} else if (activity.type === 'change-card-description') {
163+
actionDetail = 'Changed card description'
164+
} else if (activity.type === 'change-card-title') {
165+
actionDetail = 'Changed card title'
166+
}
167+
155168
cardActivities.push({
156169
user: userById[activity.userId],
157-
detail: detail,
170+
type: activity.type,
171+
actionDetail: actionDetail,
158172
when: formatDistance(new Date(activity.createdDate), now),
159173
createdDate: activity.createdDate
160174
})
@@ -263,6 +277,13 @@ export default {
263277
onAttachmentUploaded (attachment) {
264278
this.uploadingCount--
265279
this.attachments.push(attachment)
280+
if (!this.card.coverImage && attachment.previewUrl) {
281+
this.$emit('coverImageChanged', {
282+
cardId: this.card.id,
283+
cardListId: this.cardList.id,
284+
coverImage: attachment.previewUrl
285+
})
286+
}
266287
},
267288
when (createdDate) {
268289
return formatDistance(new Date(createdDate), new Date())
@@ -483,6 +504,16 @@ export default {
483504
display: inline-block;
484505
padding: .2rem 0;
485506
margin-bottom: .5rem;
507+
color: #666;
508+
}
509+
510+
.detail.add-comment {
511+
color: #000;
512+
padding: 2px 5px;
513+
border: 1px solid #eee;
514+
background: #f4f4f4;
515+
border-radius: 3px;
516+
margin-top: .2rem;
486517
}
487518
}
488519
}

front-end/src/views/BoardPage.vue

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
animation: 0, scrollSensitivity: 100, touchStartThreshold: 20}"
3333
v-bind:data-list-id="cardList.id">
3434
<div class="card-item" v-for="card in cardList.cards" v-bind:key="card.id" @click="openCard(card)">
35+
<div class="cover-image" v-if="card.coverImage"><img :src="card.coverImage" /></div>
3536
<div class="card-title">{{ card.title }}</div>
3637
</div>
3738
<div class="add-card-form-wrapper" v-if="cardList.cardForm.open">
@@ -70,7 +71,8 @@
7071
:card="openedCard"
7172
:cardList="focusedCardList"
7273
:board="board"
73-
:members="members" />
74+
:members="members"
75+
@coverImageChanged="updateCardCoverImage"/>
7476
</div>
7577
</template>
7678

@@ -386,7 +388,8 @@ export default {
386388
if (existingIndex === -1) {
387389
cardList.cards.push({
388390
id: card.id,
389-
title: card.title
391+
title: card.title,
392+
coverImage: ''
390393
})
391394
}
392395
},
@@ -401,6 +404,15 @@ export default {
401404
closeCardWindow () {
402405
console.log('[BoardPage] Close card window ' + this.openedCard.id)
403406
$('#cardModal').modal('hide')
407+
},
408+
updateCardCoverImage (change) {
409+
const cardList = this.cardLists.find(cardList => {
410+
return cardList.id === change.cardListId
411+
})
412+
const card = cardList.cards.find(card => {
413+
return card.id === change.cardId
414+
})
415+
card.coverImage = change.coverImage
404416
}
405417
}
406418
}
@@ -572,14 +584,17 @@ export default {
572584
.card-item {
573585
overflow: hidden;
574586
background: #fff;
575-
padding: 5px 8px;
576587
border-radius: 4px;
577588
margin: 0 8px 8px;
578589
box-shadow: 0 1px 0 #ccc;
579590
cursor: pointer;
580591
592+
.cover-image img {
593+
max-width: 256px;
594+
}
595+
581596
.card-title {
582-
margin: 0;
597+
margin: 5px 8px;
583598
584599
a {
585600
color: #333;

setup/2.refactoring-database.sql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,6 @@ ALTER TABLE `task_agile`.`attachment` CHANGE COLUMN `file_type` `file_type` VARC
2323
-- Add thumbnail_created to attachment
2424
ALTER TABLE `task_agile`.`attachment` ADD COLUMN `thumbnail_created` TINYINT(1) NOT NULL DEFAULT 0 AFTER `file_type`;
2525

26+
-- Add `cover_image` to `card`
27+
ALTER TABLE `task_agile`.`card` ADD COLUMN `cover_image` VARCHAR(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL AFTER `position`;
28+

src/main/java/com/taskagile/domain/application/impl/CardServiceImpl.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,12 @@ public Attachment addAttachment(AddCardAttachmentCommand command) {
128128
Card card = findCard(command.getCardId());
129129
Attachment attachment = attachmentManagement.save(
130130
command.getCardId(), command.getFile(), command.getUserId());
131+
132+
if (!card.hasCoverImage() && attachment.isThumbnailCreated()) {
133+
card.addCoverImage(attachment.getFilePath());
134+
cardRepository.save(card);
135+
}
136+
131137
domainEventPublisher.publish(new CardAttachmentAddedEvent(card, attachment, command));
132138
return attachment;
133139
}

src/main/java/com/taskagile/domain/model/card/Card.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.taskagile.domain.model.cardlist.CardList;
66
import com.taskagile.domain.model.cardlist.CardListId;
77
import com.taskagile.domain.model.user.UserId;
8+
import org.springframework.util.StringUtils;
89

910
import javax.persistence.*;
1011
import java.util.Date;
@@ -35,6 +36,9 @@ public class Card extends AbstractBaseEntity {
3536
@Column(name = "description")
3637
private String description;
3738

39+
@Column(name = "cover_image")
40+
private String coverImage;
41+
3842
@Column(name = "position")
3943
private int position;
4044

@@ -66,6 +70,14 @@ public void changeDescription(String description) {
6670
this.description = description;
6771
}
6872

73+
public boolean hasCoverImage() {
74+
return StringUtils.hasText(coverImage);
75+
}
76+
77+
public void addCoverImage(String coverImage) {
78+
this.coverImage = coverImage;
79+
}
80+
6981
public CardId getId() {
7082
return new CardId(id);
7183
}
@@ -90,6 +102,10 @@ public String getDescription() {
90102
return description;
91103
}
92104

105+
public String getCoverImage() {
106+
return coverImage;
107+
}
108+
93109
public int getPosition() {
94110
return position;
95111
}
@@ -128,6 +144,7 @@ public String toString() {
128144
", userId=" + userId +
129145
", title='" + title + '\'' +
130146
", description='" + description + '\'' +
147+
", coverImage='" + coverImage + '\'' +
131148
", position=" + position +
132149
", archived=" + archived +
133150
", createdDate=" + createdDate +

src/main/java/com/taskagile/web/apis/BoardApiController.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.taskagile.domain.application.TeamService;
77
import com.taskagile.domain.application.commands.AddBoardMemberCommand;
88
import com.taskagile.domain.application.commands.CreateBoardCommand;
9+
import com.taskagile.domain.common.file.FileUrlCreator;
910
import com.taskagile.domain.model.board.Board;
1011
import com.taskagile.domain.model.board.BoardId;
1112
import com.taskagile.domain.model.card.Card;
@@ -36,15 +37,18 @@ public class BoardApiController extends AbstractBaseController {
3637
private TeamService teamService;
3738
private CardListService cardListService;
3839
private CardService cardService;
40+
private FileUrlCreator fileUrlCreator;
3941

4042
public BoardApiController(BoardService boardService,
4143
TeamService teamService,
4244
CardListService cardListService,
43-
CardService cardService) {
45+
CardService cardService,
46+
FileUrlCreator fileUrlCreator) {
4447
this.boardService = boardService;
4548
this.teamService = teamService;
4649
this.cardListService = cardListService;
4750
this.cardService = cardService;
51+
this.fileUrlCreator = fileUrlCreator;
4852
}
4953

5054
@PostMapping("/api/boards")
@@ -74,7 +78,7 @@ public ResponseEntity<ApiResult> getBoard(@PathVariable("boardId") long rawBoard
7478
List<CardList> cardLists = cardListService.findByBoardId(boardId);
7579
List<Card> cards = cardService.findByBoardId(boardId);
7680

77-
return BoardResult.build(team, board, members, cardLists, cards);
81+
return BoardResult.build(team, board, members, cardLists, cards, fileUrlCreator);
7882
}
7983

8084
@PostMapping("/api/boards/{boardId}/members")

src/main/java/com/taskagile/web/results/BoardResult.java

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package com.taskagile.web.results;
22

3+
import com.taskagile.domain.common.file.FileUrlCreator;
34
import com.taskagile.domain.model.board.Board;
45
import com.taskagile.domain.model.card.Card;
56
import com.taskagile.domain.model.cardlist.CardList;
67
import com.taskagile.domain.model.cardlist.CardListId;
78
import com.taskagile.domain.model.team.Team;
89
import com.taskagile.domain.model.user.User;
10+
import com.taskagile.utils.ImageUtils;
911
import org.springframework.http.ResponseEntity;
1012

1113
import java.util.ArrayList;
@@ -16,7 +18,8 @@
1618
public class BoardResult {
1719

1820
public static ResponseEntity<ApiResult> build(Team team, Board board, List<User> members,
19-
List<CardList> cardLists, List<Card> cards) {
21+
List<CardList> cardLists, List<Card> cards,
22+
FileUrlCreator fileUrlCreator) {
2023
Map<String, Object> boardData = new HashMap<>();
2124
boardData.put("id", board.getId().value());
2225
boardData.put("name", board.getName());
@@ -34,7 +37,7 @@ public static ResponseEntity<ApiResult> build(Team team, Board board, List<User>
3437
}
3538

3639
for (CardList cardList: cardLists) {
37-
cardListsData.add(new CardListData(cardList, cardsByList.get(cardList.getId())));
40+
cardListsData.add(new CardListData(cardList, cardsByList.get(cardList.getId()), fileUrlCreator));
3841
}
3942

4043
ApiResult result = ApiResult.blank()
@@ -80,13 +83,13 @@ private static class CardListData {
8083
private int position;
8184
private List<CardData> cards = new ArrayList<>();
8285

83-
CardListData(CardList cardList, List<Card> cards) {
86+
CardListData(CardList cardList, List<Card> cards, FileUrlCreator fileUrlCreator) {
8487
this.id = cardList.getId().value();
8588
this.name = cardList.getName();
8689
this.position = cardList.getPosition();
8790
if (cards != null) {
8891
for (Card card: cards) {
89-
this.cards.add(new CardData(card));
92+
this.cards.add(new CardData(card, fileUrlCreator));
9093
}
9194
}
9295
}
@@ -112,11 +115,14 @@ private static class CardData {
112115
private long id;
113116
private String title;
114117
private int position;
118+
private String coverImage;
115119

116-
CardData(Card card) {
120+
CardData(Card card, FileUrlCreator fileUrlCreator) {
117121
this.id = card.getId().value();
118122
this.title = card.getTitle();
119123
this.position = card.getPosition();
124+
this.coverImage = card.hasCoverImage() ?
125+
ImageUtils.getThumbnailVersion(fileUrlCreator.url(card.getCoverImage())) : "";
120126
}
121127

122128
public long getId() {
@@ -130,6 +136,10 @@ public String getTitle() {
130136
public int getPosition() {
131137
return position;
132138
}
139+
140+
public String getCoverImage() {
141+
return coverImage;
142+
}
133143
}
134144

135145
}

0 commit comments

Comments
 (0)