Merge pull request #3793 from nextcloud/enh/upcomming_card_optimisation

Optimise upcomming overview creation
This commit is contained in:
Julius Härtl
2023-02-15 13:45:44 +01:00
committed by GitHub
8 changed files with 121 additions and 125 deletions

View File

@@ -158,6 +158,20 @@ class Card extends RelationalEntity {
return $calendar;
}
public function getDaysUntilDue(): ?int {
$today = new DateTime();
$match_date = $this->getDuedate();
if ($match_date === null) {
return null;
}
$today->setTime(0, 0);
$match_date->setTime(0, 0);
$diff = $today->diff($match_date);
return (int) $diff->format('%R%a'); // Extract days count in interval
}
public function getCalendarPrefix(): string {
return 'card';
}

View File

@@ -127,7 +127,7 @@ class RelationalEntity extends Entity implements \JsonSerializable {
}
}
public function __call($methodName, $args) {
public function __call(string $methodName, array $args) {
$attr = lcfirst(substr($methodName, 7));
if (array_key_exists($attr, $this->_resolvedProperties) && strpos($methodName, 'resolve') === 0) {
if ($this->_resolvedProperties[$attr] !== null) {

View File

@@ -39,6 +39,10 @@ class BoardSummary extends Board {
];
}
protected function getter(string $name): mixed {
return $this->board->getter($name);
}
public function __call($name, $arguments) {
return $this->board->__call($name, $arguments);
}

View File

@@ -22,7 +22,6 @@
*/
namespace OCA\Deck\Model;
use DateTime;
use OCA\Deck\Db\Board;
use OCA\Deck\Db\Card;
@@ -41,6 +40,14 @@ class CardDetails extends Card {
}
public function jsonSerialize(array $extras = []): array {
$array = parent::jsonSerialize();
$array['overdue'] = $this->getDueStatus();
unset($array['notified']);
unset($array['descriptionPrev']);
unset($array['relatedStack']);
unset($array['relatedBoard']);
$array = $this->card->jsonSerialize();
unset($array['notified'], $array['descriptionPrev'], $array['relatedStack'], $array['relatedBoard']);
@@ -51,30 +58,18 @@ class CardDetails extends Card {
}
private function getDueStatus(): int {
$today = new DateTime();
$today->setTime(0, 0);
$match_date = $this->card->getDuedate();
if (!$match_date) {
return Card::DUEDATE_FUTURE;
$diffDays = $this->getDaysUntilDue();
if ($diffDays === null || $diffDays > 1) {
return static::DUEDATE_FUTURE;
}
$match_date->setTime(0, 0);
$diff = $today->diff($match_date);
$diffDays = (int) $diff->format('%R%a'); // Extract days count in interval
if ($diffDays === 1) {
return Card::DUEDATE_NEXT;
return static::DUEDATE_NEXT;
}
if ($diffDays === 0) {
return Card::DUEDATE_NOW;
}
if ($diffDays < 0) {
return Card::DUEDATE_OVERDUE;
return static::DUEDATE_NOW;
}
return Card::DUEDATE_FUTURE;
return static::DUEDATE_OVERDUE;
}
private function appendBoardDetails(&$array): void {
@@ -86,7 +81,11 @@ class CardDetails extends Card {
$array['board'] = (new BoardSummary($this->board))->jsonSerialize();
}
public function __call($name, $arguments) {
return $this->card->__call($name, $arguments);
protected function getter(string $name): mixed {
return $this->card->getter($name);
}
public function __call(string $methodName, array $args) {
return $this->card->__call($methodName, $args);
}
}

View File

@@ -93,7 +93,7 @@ class OverviewService {
public function findUpcomingCards(string $userId): array {
$userBoards = $this->boardMapper->findAllForUser($userId);
$foundCards = [];
$overview = [];
foreach ($userBoards as $userBoard) {
if (count($userBoard->getAcl()) === 0) {
// private board: get cards with due date
@@ -103,14 +103,27 @@ class OverviewService {
$cards = $this->cardMapper->findToMeOrNotAssignedCards($userBoard->getId(), $userId);
}
$foundCards[] = array_map(
function (Card $card) use ($userBoard, $userId) {
$this->enrich($card, $userId);
return (new CardDetails($card, $userBoard))->jsonSerialize();
},
$cards
);
foreach ($cards as $card) {
$this->enrich($card, $userId);
$diffDays = $card->getDaysUntilDue();
$key = 'later';
if ($diffDays === null) {
$key = 'nodue';
} elseif ($diffDays < 0) {
$key = 'overdue';
} elseif ($diffDays === 0) {
$key = 'today';
} elseif ($diffDays === 1) {
$key = 'tomorrow';
} elseif ($diffDays <= 7) {
$key = 'nextSevenDays';
}
$card = (new CardDetails($card, $userBoard));
$overview[$key][] = $card->jsonSerialize();
}
}
return array_merge(...$foundCards);
return $overview;
}
}

View File

@@ -31,44 +31,44 @@
</div>
<div v-else-if="isValidFilter" class="overview">
<div v-if="cardsByDueDate.overdue.length > 0" class="dashboard-column">
<div v-if="assignedCardsDashboard.length > 0" class="dashboard-column">
<h3>{{ t('deck', 'Overdue') }}</h3>
<div v-for="card in cardsByDueDate.overdue" :key="card.id">
<div v-for="card in assignedCardsDashboard.overdue" :key="card.id">
<CardItem :id="card.id" />
</div>
</div>
<div class="dashboard-column">
<h3>{{ t('deck', 'Today') }}</h3>
<div v-for="card in cardsByDueDate.today" :key="card.id">
<div v-for="card in assignedCardsDashboard.today" :key="card.id">
<CardItem :id="card.id" />
</div>
</div>
<div class="dashboard-column">
<h3>{{ t('deck', 'Tomorrow') }}</h3>
<div v-for="card in cardsByDueDate.tomorrow" :key="card.id">
<div v-for="card in assignedCardsDashboard.tomorrow" :key="card.id">
<CardItem :id="card.id" />
</div>
</div>
<div class="dashboard-column">
<h3>{{ t('deck', 'Next 7 days') }}</h3>
<div v-for="card in cardsByDueDate.nextSevenDays" :key="card.id">
<div v-for="card in assignedCardsDashboard.nextSevenDays" :key="card.id">
<CardItem :id="card.id" />
</div>
</div>
<div class="dashboard-column">
<h3>{{ t('deck', 'Later') }}</h3>
<div v-for="card in cardsByDueDate.later" :key="card.id">
<div v-for="card in assignedCardsDashboard.later" :key="card.id">
<CardItem :id="card.id" />
</div>
</div>
<div class="dashboard-column">
<h3>{{ t('deck', 'No due') }}</h3>
<div v-for="card in cardsByDueDate.nodue" :key="card.id">
<div v-for="card in assignedCardsDashboard.nodue" :key="card.id">
<CardItem :id="card.id" />
</div>
</div>
@@ -83,7 +83,6 @@
import Controls from '../Controls.vue'
import CardItem from '../cards/CardItem.vue'
import { mapGetters } from 'vuex'
import moment from '@nextcloud/moment'
import GlobalSearchResults from '../search/GlobalSearchResults.vue'
const FILTER_UPCOMING = 'upcoming'
@@ -125,13 +124,6 @@ export default {
...mapGetters([
'assignedCardsDashboard',
]),
cardsByDueDate() {
switch (this.filter) {
case FILTER_UPCOMING:
return this.groupByDue(this.assignedCardsDashboard)
}
return null
},
},
watch: {
'$route.params.filter'() {
@@ -153,47 +145,6 @@ export default {
}
this.loading = false
},
groupByDue(dataset) {
const all = {
nodue: [],
overdue: [],
today: [],
tomorrow: [],
nextSevenDays: [],
later: [],
}
dataset.forEach(card => {
if (card.duedate === null) {
all.nodue.push(card)
} else {
const hours = Math.floor(moment(card.duedate).diff(this.$root.time, 'seconds') / 60 / 60)
const d = new Date()
const currentHour = d.getHours()
if (hours < 0) {
all.overdue.push(card)
}
if (hours >= 0 && hours < (24 - currentHour)) {
all.today.push(card)
}
if (hours >= (24 - currentHour) && hours < (48 - currentHour)) {
all.tomorrow.push(card)
}
if (hours >= (48 - currentHour) && hours < (24 * 7)) {
all.nextSevenDays.push(card)
}
if (hours >= (24 * 7)) {
all.later.push(card)
}
}
})
Object.keys(all).forEach((list) => {
all[list] = all[list].sort((a, b) => {
return (new Date(a.duedate)).getTime() - (new Date(b.duedate)).getTime()
})
})
return all
},
},
}

View File

@@ -43,12 +43,14 @@ export default {
actions: {
async loadUpcoming({ commit }) {
commit('setCurrentBoard', null)
const assignedCards = await apiClient.get('upcoming')
const assignedCardsFlat = assignedCards.flat()
for (const i in assignedCardsFlat) {
commit('addCard', assignedCardsFlat[i])
const upcommingCards = await apiClient.get('upcoming')
for (const dueStatus in upcommingCards) {
for (const idx in upcommingCards[dueStatus]) {
commit('addCard', upcommingCards[dueStatus][idx])
}
}
commit('setAssignedCards', assignedCardsFlat)
commit('setAssignedCards', upcommingCards)
},
},
}

View File

@@ -1,40 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<files psalm-version="5.4.0@62db5d4f6a7ae0a20f7cc5a4952d730272fc0863">
<files psalm-version="5.6.0@e784128902dfe01d489c4123d69918a9f3c1eac5">
<file src="lib/Activity/Filter.php">
<MethodSignatureMismatch occurrences="1">
<MethodSignatureMismatch>
<code>$types</code>
</MethodSignatureMismatch>
</file>
<file src="lib/Command/UserExport.php">
<ImplementedReturnTypeMismatch occurrences="1">
<ImplementedReturnTypeMismatch>
<code>void</code>
</ImplementedReturnTypeMismatch>
<UndefinedThisPropertyAssignment occurrences="2">
<UndefinedThisPropertyAssignment>
<code>$this-&gt;boardMapper</code>
<code>$this-&gt;stackMapper</code>
</UndefinedThisPropertyAssignment>
<UndefinedThisPropertyFetch occurrences="2">
<UndefinedThisPropertyFetch>
<code>$this-&gt;boardMapper</code>
<code>$this-&gt;stackMapper</code>
</UndefinedThisPropertyFetch>
</file>
<file src="lib/Controller/BoardApiController.php">
<TypeDoesNotContainNull occurrences="2">
<TypeDoesNotContainNull>
<code>$modified === null</code>
<code>$modified === null</code>
</TypeDoesNotContainNull>
<UndefinedClass occurrences="1">
<UndefinedClass>
<code>Util</code>
</UndefinedClass>
<UndefinedThisPropertyAssignment occurrences="1">
<UndefinedThisPropertyAssignment>
<code>$this-&gt;userId</code>
</UndefinedThisPropertyAssignment>
<UndefinedThisPropertyFetch occurrences="1">
<UndefinedThisPropertyFetch>
<code>$this-&gt;userId</code>
</UndefinedThisPropertyFetch>
</file>
<file src="lib/Controller/CommentsApiController.php">
<InvalidScalarArgument occurrences="6">
<InvalidScalarArgument>
<code>$cardId</code>
<code>$cardId</code>
<code>$cardId</code>
@@ -44,95 +44,108 @@
</InvalidScalarArgument>
</file>
<file src="lib/Controller/PageController.php">
<UndefinedClass occurrences="1">
<UndefinedClass>
<code>LoadSidebar</code>
</UndefinedClass>
</file>
<file src="lib/Controller/StackApiController.php">
<RedundantCondition occurrences="1">
<RedundantCondition>
<code>$modified !== null</code>
</RedundantCondition>
<UndefinedClass occurrences="1">
<UndefinedClass>
<code>Util</code>
</UndefinedClass>
</file>
<file src="lib/DAV/Calendar.php">
<UndefinedClass occurrences="1">
<UndefinedClass>
<code>ExternalCalendar</code>
</UndefinedClass>
</file>
<file src="lib/DAV/CalendarObject.php">
<UndefinedClass occurrences="1">
<UndefinedClass>
<code>ICalendarObject</code>
</UndefinedClass>
</file>
<file src="lib/DAV/CalendarPlugin.php">
<UndefinedClass occurrences="1">
<UndefinedClass>
<code>ICalendarProvider</code>
</UndefinedClass>
</file>
<file src="lib/DAV/DeckCalendarBackend.php">
<UndefinedClass occurrences="1">
<UndefinedClass>
<code>NotFound</code>
</UndefinedClass>
</file>
<file src="lib/Db/Card.php">
<UndefinedClass occurrences="2">
<UndefinedClass>
<code>VCalendar</code>
<code>VCalendar</code>
</UndefinedClass>
</file>
<file src="lib/Db/CardMapper.php">
<InvalidScalarArgument occurrences="1">
<InvalidScalarArgument>
<code>$entity-&gt;getId()</code>
</InvalidScalarArgument>
<UndefinedInterfaceMethod occurrences="1">
<UndefinedInterfaceMethod>
<code>getUserIdGroups</code>
</UndefinedInterfaceMethod>
</file>
<file src="lib/Db/LabelMapper.php">
<ParamNameMismatch occurrences="1">
<ParamNameMismatch>
<code>$labelId</code>
</ParamNameMismatch>
</file>
<file src="lib/Db/RelationalEntity.php">
<MethodSignatureMismatch occurrences="1">
<code>$attribute</code>
</MethodSignatureMismatch>
</file>
<file src="lib/Db/Stack.php">
<UndefinedClass occurrences="2">
<UndefinedClass>
<code>VCalendar</code>
<code>VCalendar</code>
</UndefinedClass>
</file>
<file src="lib/Model/BoardSummary.php">
<ConstructorSignatureMismatch>
<code>public function __construct(Board $board) {</code>
<code>public function __construct(Board $board) {</code>
</ConstructorSignatureMismatch>
</file>
<file src="lib/Model/CardDetails.php">
<ConstructorSignatureMismatch>
<code>public function __construct(Card $card, ?Board $board = null) {</code>
<code>public function __construct(Card $card, ?Board $board = null) {</code>
</ConstructorSignatureMismatch>
</file>
<file src="lib/Service/AttachmentService.php">
<InvalidCatch occurrences="1"/>
<InvalidCatch>
<code>try {
$attachment = $this-&gt;attachmentMapper-&gt;find($attachmentId);
} catch (IMapperException $e) {
throw new NoPermissionException('Permission denied');
}</code>
</InvalidCatch>
</file>
<file src="lib/Service/BoardService.php">
<TooManyArguments occurrences="2">
<TooManyArguments>
<code>findAll</code>
<code>findAll</code>
</TooManyArguments>
</file>
<file src="lib/Service/CirclesService.php">
<RedundantCondition occurrences="1">
<RedundantCondition>
<code>$member !== null</code>
</RedundantCondition>
</file>
<file src="lib/Service/FileService.php">
<RedundantCondition occurrences="2">
<RedundantCondition>
<code>is_resource($content)</code>
<code>is_resource($content)</code>
</RedundantCondition>
</file>
<file src="lib/Sharing/DeckShareProvider.php">
<InvalidReturnType occurrences="1">
<InvalidReturnType>
<code>getShareByToken</code>
</InvalidReturnType>
</file>
<file src="lib/Sharing/Listener.php">
<InvalidArgument occurrences="1">
<InvalidArgument>
<code>[self::class, 'listenPreShare']</code>
</InvalidArgument>
</file>