Compare commits

..

12 Commits

Author SHA1 Message Date
Julius Härtl
31580bba45 Fix eslint warnings
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2022-05-12 09:02:52 +02:00
Julius Härtl
7a4432f552 Move to vue-material-design-icons
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2022-05-12 08:21:59 +02:00
Julius Härtl
a8e444fd1f Move global deck icon to plain css
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2022-05-12 08:12:24 +02:00
Julius Härtl
2c7708dab1 Merge pull request #3809 from nextcloud/bugfix/cs-fix
Fix php-cs-fixer failure
2022-05-11 23:40:50 +02:00
Julius Härtl
e156ff77f8 Merge pull request #3808 from nextcloud/bugfix/eslint-root
Make eslint stop reading configs at the root
2022-05-11 22:03:45 +02:00
Julius Härtl
5f5f22ee8c Fix php-cs-fixer failure
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2022-05-11 21:47:05 +02:00
Julius Härtl
011b60b3bf Make eslint stop reading configs at the root
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2022-05-11 21:42:44 +02:00
Julius Härtl
9bd8669cf4 Merge pull request #3682 from nextcloud/bug/increase-file-count-after-sharing
Increase file count after sharing
2022-05-11 16:40:42 +02:00
Julius Härtl
03f400620e Move all caching to helper
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2022-05-11 16:04:12 +02:00
Luka Trovic
ed3be361b5 fix: move shares count cache logic to the DeckShareProvider
Signed-off-by: Luka Trovic <luka@nextcloud.com>

fix: conflicts

Signed-off-by: Luka Trovic <luka@nextcloud.com>

fix: conflicts and test issues

Signed-off-by: Luka Trovic <luka@nextcloud.com>
2022-05-06 10:25:48 +02:00
Luka Trovic
0b6990f828 fix: update attachments count when sharing
Signed-off-by: Luka Trovic <luka@nextcloud.com>
2022-05-06 10:24:32 +02:00
Luka Trovic
2af94410f5 fix: increase file count after sharing
Signed-off-by: Luka Trovic <luka@nextcloud.com>
2022-05-06 10:24:32 +02:00
50 changed files with 238 additions and 149 deletions

View File

@@ -1,4 +1,5 @@
module.exports = {
root: true,
extends: [
'@nextcloud',
],

View File

@@ -0,0 +1,52 @@
<?php
/*
* @copyright Copyright (c) 2020 Julius Härtl <jus@bitgrid.net>
*
* @author Julius Härtl <jus@bitgrid.net>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
declare(strict_types=1);
namespace OCA\Deck\Cache;
use OCP\ICache;
use OCP\ICacheFactory;
class AttachmentCacheHelper {
/** @var ICache */
private $cache;
public function __construct(ICacheFactory $cacheFactory) {
$this->cache = $cacheFactory->createDistributed('deck-attachments');
}
public function getAttachmentCount(int $cardId): ?int {
return $this->cache->get('count-' . $cardId);
}
public function setAttachmentCount(int $cardId, int $count): void {
$this->cache->set('count-' . $cardId, $count);
}
public function clearAttachmentCount(int $cardId): void {
$this->cache->remove('count-' . $cardId);
}
}

View File

@@ -34,11 +34,10 @@ use OCA\Deck\Db\ChangeHelper;
use OCA\Deck\InvalidAttachmentType;
use OCA\Deck\NoPermissionException;
use OCA\Deck\NotFoundException;
use OCA\Deck\Cache\AttachmentCacheHelper;
use OCA\Deck\StatusException;
use OCP\AppFramework\Db\IMapperException;
use OCP\AppFramework\Http\Response;
use OCP\ICache;
use OCP\ICacheFactory;
use OCP\IL10N;
class AttachmentService {
@@ -49,9 +48,10 @@ class AttachmentService {
/** @var IAttachmentService[] */
private $services = [];
/** @var Application */
private $application;
/** @var ICache */
private $cache;
/** @var AttachmentCacheHelper */
private $attachmentCacheHelper;
/** @var IL10N */
private $l10n;
/** @var ActivityManager */
@@ -59,13 +59,13 @@ class AttachmentService {
/** @var ChangeHelper */
private $changeHelper;
public function __construct(AttachmentMapper $attachmentMapper, CardMapper $cardMapper, ChangeHelper $changeHelper, PermissionService $permissionService, Application $application, ICacheFactory $cacheFactory, $userId, IL10N $l10n, ActivityManager $activityManager) {
public function __construct(AttachmentMapper $attachmentMapper, CardMapper $cardMapper, ChangeHelper $changeHelper, PermissionService $permissionService, Application $application, AttachmentCacheHelper $attachmentCacheHelper, $userId, IL10N $l10n, ActivityManager $activityManager) {
$this->attachmentMapper = $attachmentMapper;
$this->cardMapper = $cardMapper;
$this->permissionService = $permissionService;
$this->userId = $userId;
$this->application = $application;
$this->cache = $cacheFactory->createDistributed('deck-card-attachments-');
$this->attachmentCacheHelper = $attachmentCacheHelper;
$this->l10n = $l10n;
$this->activityManager = $activityManager;
$this->changeHelper = $changeHelper;
@@ -139,14 +139,16 @@ class AttachmentService {
* @param $cardId
* @return int|mixed
* @throws BadRequestException
* @throws InvalidAttachmentType
* @throws \OCP\DB\Exception
*/
public function count($cardId) {
if (is_numeric($cardId) === false) {
throw new BadRequestException('card id must be a number');
}
$count = $this->cache->get('card-' . $cardId);
if (!$count) {
$count = $this->attachmentCacheHelper->getAttachmentCount((int)$cardId);
if ($count === null) {
$count = count($this->attachmentMapper->findAll($cardId));
foreach (array_keys($this->services) as $attachmentType) {
@@ -156,7 +158,7 @@ class AttachmentService {
}
}
$this->cache->set('card-' . $cardId, $count);
$this->attachmentCacheHelper->setAttachmentCount((int)$cardId, $count);
}
return $count;
@@ -186,7 +188,7 @@ class AttachmentService {
$this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT);
$this->cache->clear('card-' . $cardId);
$this->attachmentCacheHelper->clearAttachmentCount((int)$cardId);
$attachment = new Attachment();
$attachment->setCardId($cardId);
$attachment->setType($type);
@@ -298,7 +300,7 @@ class AttachmentService {
}
$this->permissionService->checkPermission($this->cardMapper, $attachment->getCardId(), Acl::PERMISSION_EDIT);
$this->cache->clear('card-' . $attachment->getCardId());
$this->attachmentCacheHelper->clearAttachmentCount($cardId);
$attachment->setData($data);
try {
@@ -356,7 +358,7 @@ class AttachmentService {
}
}
$this->cache->clear('card-' . $attachment->getCardId());
$this->attachmentCacheHelper->clearAttachmentCount($cardId);
$this->changeHelper->cardChanged($attachment->getCardId());
$this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_CARD, $attachment, ActivityManager::SUBJECT_ATTACHMENT_DELETE);
return $attachment;
@@ -370,7 +372,7 @@ class AttachmentService {
}
$this->permissionService->checkPermission($this->cardMapper, $attachment->getCardId(), Acl::PERMISSION_EDIT);
$this->cache->clear('card-' . $attachment->getCardId());
$this->attachmentCacheHelper->clearAttachmentCount($cardId);
try {
$service = $this->getService($attachment->getType());

View File

@@ -27,6 +27,7 @@ declare(strict_types=1);
namespace OCA\Deck\Sharing;
use OC\Files\Cache\Cache;
use OCA\Deck\Cache\AttachmentCacheHelper;
use OCA\Deck\Db\Acl;
use OCA\Deck\Db\Board;
use OCA\Deck\Db\BoardMapper;
@@ -45,7 +46,6 @@ use OCP\Files\IMimeTypeLoader;
use OCP\Files\Node;
use OCP\IDBConnection;
use OCP\IL10N;
use OCP\Security\ISecureRandom;
use OCP\Share\Exceptions\GenericShareException;
use OCP\Share\Exceptions\ShareNotFound;
use OCP\Share\IManager;
@@ -69,6 +69,8 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
private $dbConnection;
/** @var IManager */
private $shareManager;
/** @var AttachmentCacheHelper */
private $attachmentCacheHelper;
/** @var BoardMapper */
private $boardMapper;
/** @var CardMapper */
@@ -77,14 +79,25 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
private $permissionService;
/** @var ITimeFactory */
private $timeFactory;
/** @var IL10N */
private $l;
public function __construct(IDBConnection $connection, IManager $shareManager, ISecureRandom $secureRandom, BoardMapper $boardMapper, CardMapper $cardMapper, PermissionService $permissionService, IL10N $l) {
public function __construct(
IDBConnection $connection,
IManager $shareManager,
BoardMapper $boardMapper,
CardMapper $cardMapper,
PermissionService $permissionService,
AttachmentCacheHelper $attachmentCacheHelper,
IL10N $l
) {
$this->dbConnection = $connection;
$this->shareManager = $shareManager;
$this->boardMapper = $boardMapper;
$this->cardMapper = $cardMapper;
$this->attachmentCacheHelper = $attachmentCacheHelper;
$this->permissionService = $permissionService;
$this->l = $l;
$this->timeFactory = \OC::$server->get(ITimeFactory::class);
}
@@ -152,6 +165,8 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
);
$data = $this->getRawShare($shareId);
$this->attachmentCacheHelper->clearAttachmentCount((int)$cardId);
return $this->createShareObject($data);
}
@@ -339,6 +354,8 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
$qb->orWhere($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId())));
$qb->execute();
$this->attachmentCacheHelper->clearAttachmentCount((int)$share->getSharedWith());
}
/**

View File

@@ -43,11 +43,10 @@
<script>
import { mapState } from 'vuex'
import AppNavigation from './components/navigation/AppNavigation'
import { Modal, Content, AppContent } from '@nextcloud/vue'
import { BoardApi } from './services/BoardApi'
import { emit, subscribe } from '@nextcloud/event-bus'
import AppNavigation from './components/navigation/AppNavigation.vue'
import { BoardApi } from './services/BoardApi.js'
const boardApi = new BoardApi()
export default {
@@ -158,7 +157,6 @@ export default {
<style lang="scss">
@import "../css/print";
.icon-activity {
background-image: url(../img/activity-dark.svg);

View File

@@ -96,7 +96,7 @@ import Modal from '@nextcloud/vue/dist/Components/Modal'
import Multiselect from '@nextcloud/vue/dist/Components/Multiselect'
import EmptyContent from '@nextcloud/vue/dist/Components/EmptyContent'
import axios from '@nextcloud/axios'
import { CardApi } from './services/CardApi'
import { CardApi } from './services/CardApi.js'
const cardApi = new CardApi()

View File

@@ -30,7 +30,9 @@
</div>
</div>
<!-- FIXME ins/del tags do no longer work with activity so we should get rid of that -->
<!-- eslint-disable vue/no-v-html -->
<p v-if="activity.message" class="activity--message" v-html="sanitizedMessage" />
<!-- eslint-enable -->
</div>
</template>
@@ -39,7 +41,7 @@ import RichText from '@juliushaertl/vue-richtext'
import { UserBubble } from '@nextcloud/vue'
import moment from '@nextcloud/moment'
import DOMPurify from 'dompurify'
import relativeDate from '../mixins/relativeDate'
import relativeDate from '../mixins/relativeDate.js'
const InternalLink = {
name: 'InternalLink',

View File

@@ -37,7 +37,7 @@
<script>
import axios from '@nextcloud/axios'
import { generateOcsUrl } from '@nextcloud/router'
import ActivityEntry from './ActivityEntry'
import ActivityEntry from './ActivityEntry.vue'
import InfiniteLoading from 'vue-infinite-loading'
const ACTIVITY_FETCH_LIMIT = 50

View File

@@ -63,7 +63,7 @@
<script>
import { Modal } from '@nextcloud/vue'
import attachmentUpload from '../mixins/attachmentUpload'
import attachmentUpload from '../mixins/attachmentUpload.js'
import { loadState } from '@nextcloud/initial-state'
let maxUploadSizeState

View File

@@ -203,8 +203,8 @@
<script>
import { mapState, mapGetters } from 'vuex'
import { Actions, ActionButton, Popover, Avatar } from '@nextcloud/vue'
import labelStyle from '../mixins/labelStyle'
import CardCreateDialog from '../CardCreateDialog'
import labelStyle from '../mixins/labelStyle.js'
import CardCreateDialog from '../CardCreateDialog.vue'
import ArchiveIcon from 'vue-material-design-icons/Archive'
import FilterIcon from 'vue-material-design-icons/Filter'
import FilterOffIcon from 'vue-material-design-icons/FilterOff'

View File

@@ -72,12 +72,12 @@
<script>
import { Container, Draggable } from 'vue-smooth-dnd'
import { mapState, mapGetters } from 'vuex'
import Controls from '../Controls'
import Stack from './Stack'
import { EmptyContent } from '@nextcloud/vue'
import GlobalSearchResults from '../search/GlobalSearchResults'
import { showError } from '../../helpers/errors'
import { mapState, mapGetters } from 'vuex'
import Controls from '../Controls.vue'
import Stack from './Stack.vue'
import GlobalSearchResults from '../search/GlobalSearchResults.vue'
import { showError } from '../../helpers/errors.js'
export default {
name: 'Board',

View File

@@ -59,10 +59,10 @@
<script>
import { mapState, mapGetters } from 'vuex'
import SharingTabSidebar from './SharingTabSidebar'
import TagsTabSidebar from './TagsTabSidebar'
import DeletedTabSidebar from './DeletedTabSidebar'
import TimelineTabSidebar from './TimelineTabSidebar'
import SharingTabSidebar from './SharingTabSidebar.vue'
import TagsTabSidebar from './TagsTabSidebar.vue'
import DeletedTabSidebar from './DeletedTabSidebar.vue'
import TimelineTabSidebar from './TimelineTabSidebar.vue'
import { AppSidebar, AppSidebarTab } from '@nextcloud/vue'
const capabilities = window.OC.getCapabilities()

View File

@@ -32,7 +32,7 @@
<script>
import { mapState } from 'vuex'
import relativeDate from '../../mixins/relativeDate'
import relativeDate from '../../mixins/relativeDate.js'
export default {
name: 'DeletedTabSidebar',

View File

@@ -121,7 +121,7 @@ import { Container, Draggable } from 'vue-smooth-dnd'
import { Actions, ActionButton, Modal } from '@nextcloud/vue'
import { showError, showUndo } from '@nextcloud/dialogs'
import CardItem from '../cards/CardItem'
import CardItem from '../cards/CardItem.vue'
import '@nextcloud/dialogs/styles/toast.scss'
import ArchiveIcon from 'vue-material-design-icons/Archive'

View File

@@ -70,7 +70,7 @@
<script>
import { mapGetters } from 'vuex'
import Color from '../../mixins/color'
import Color from '../../mixins/color.js'
import { ColorPicker, Actions, ActionButton } from '@nextcloud/vue'
export default {

View File

@@ -7,7 +7,7 @@
</template>
<script>
import ActivityList from '../ActivityList'
import ActivityList from '../ActivityList.vue'
export default {
name: 'TimelineTabSidebar',

View File

@@ -43,8 +43,8 @@
<script>
import BoardItem from './BoardItem'
import Controls from '../Controls'
import BoardItem from './BoardItem.vue'
import Controls from '../Controls.vue'
export default {
name: 'Boards',

View File

@@ -104,15 +104,16 @@
<script>
import axios from '@nextcloud/axios'
import { Actions, ActionButton, ActionLink } from '@nextcloud/vue'
import AttachmentDragAndDrop from '../AttachmentDragAndDrop'
import relativeDate from '../../mixins/relativeDate'
import { formatFileSize } from '@nextcloud/files'
import { getCurrentUser } from '@nextcloud/auth'
import { generateUrl, generateOcsUrl, generateRemoteUrl } from '@nextcloud/router'
import { mapState } from 'vuex'
import { mapState, mapActions } from 'vuex'
import { loadState } from '@nextcloud/initial-state'
import attachmentUpload from '../../mixins/attachmentUpload'
import { getFilePickerBuilder } from '@nextcloud/dialogs'
import AttachmentDragAndDrop from '../AttachmentDragAndDrop.vue'
import relativeDate from '../../mixins/relativeDate.js'
import attachmentUpload from '../../mixins/attachmentUpload.js'
const maxUploadSizeState = loadState('deck', 'maxUploadSize')
const picker = getFilePickerBuilder(t('deck', 'File to share'))
@@ -205,11 +206,14 @@ export default {
cardId: {
immediate: true,
handler() {
this.$store.dispatch('fetchAttachments', this.cardId)
this.fetchAttachments(this.cardId)
},
},
},
methods: {
...mapActions([
'fetchAttachments',
]),
handleUploadFile(event) {
const files = event.target.files ?? []
for (const file of files) {
@@ -233,7 +237,7 @@ export default {
shareType: 12,
shareWith: '' + this.cardId,
}).then(() => {
this.$store.dispatch('fetchAttachments', this.cardId)
this.fetchAttachments(this.cardId)
})
})
},

View File

@@ -84,17 +84,16 @@
<script>
import { ActionButton, AppSidebar, AppSidebarTab } from '@nextcloud/vue'
import { generateUrl } from '@nextcloud/router'
import { mapState, mapGetters } from 'vuex'
import CardSidebarTabDetails from './CardSidebarTabDetails'
import CardSidebarTabAttachments from './CardSidebarTabAttachments'
import CardSidebarTabComments from './CardSidebarTabComments'
import CardSidebarTabActivity from './CardSidebarTabActivity'
import relativeDate from '../../mixins/relativeDate'
import moment from '@nextcloud/moment'
import AttachmentIcon from 'vue-material-design-icons/Paperclip.vue'
import { showError } from '@nextcloud/dialogs'
import { getLocale } from '@nextcloud/l10n'
import moment from '@nextcloud/moment'
import { mapState, mapGetters } from 'vuex'
import AttachmentIcon from 'vue-material-design-icons/Paperclip.vue'
import CardSidebarTabDetails from './CardSidebarTabDetails.vue'
import CardSidebarTabAttachments from './CardSidebarTabAttachments.vue'
import CardSidebarTabComments from './CardSidebarTabComments.vue'
import CardSidebarTabActivity from './CardSidebarTabActivity.vue'
import relativeDate from '../../mixins/relativeDate.js'
const capabilities = window.OC.getCapabilities()

View File

@@ -30,7 +30,7 @@
</template>
<script>
import ActivityList from '../ActivityList'
import ActivityList from '../ActivityList.vue'
export default {
name: 'CardSidebarTabActivity',

View File

@@ -28,7 +28,7 @@
</template>
<script>
import AttachmentList from './AttachmentList'
import AttachmentList from './AttachmentList.vue'
export default {
name: 'CardSidebarTabAttachments',
components: {

View File

@@ -36,8 +36,8 @@
<script>
import { mapState, mapGetters } from 'vuex'
import { Avatar } from '@nextcloud/vue'
import CommentItem from './CommentItem'
import CommentForm from './CommentForm'
import CommentItem from './CommentItem.vue'
import CommentForm from './CommentForm.vue'
import InfiniteLoading from 'vue-infinite-loading'
import { getCurrentUser } from '@nextcloud/auth'

View File

@@ -128,14 +128,14 @@ import moment from '@nextcloud/moment'
import { Avatar, Actions, ActionButton, Multiselect, DatetimePicker } from '@nextcloud/vue'
import { CollectionList } from 'nextcloud-vue-collections'
import Color from '../../mixins/color'
import Color from '../../mixins/color.js'
import {
getLocale,
getDayNamesMin,
getFirstDay,
getMonthNamesShort,
} from '@nextcloud/l10n'
import Description from './Description'
import Description from './Description.vue'
export default {
name: 'CardSidebarTabDetails',

View File

@@ -65,7 +65,7 @@
import { mapState } from 'vuex'
import { UserBubble, Avatar } from '@nextcloud/vue'
import At from 'vue-at'
import { rawToParsed } from '../../helpers/mentions'
import { rawToParsed } from '../../helpers/mentions.js'
export default {
name: 'CommentForm',

View File

@@ -66,10 +66,10 @@
<script>
import { Avatar, Actions, ActionButton, UserBubble } from '@nextcloud/vue'
import RichText from '@juliushaertl/vue-richtext'
import CommentForm from './CommentForm'
import CommentForm from './CommentForm.vue'
import { getCurrentUser } from '@nextcloud/auth'
import md5 from 'blueimp-md5'
import relativeDate from '../../mixins/relativeDate'
import relativeDate from '../../mixins/relativeDate.js'
import ReplyIcon from 'vue-material-design-icons/Reply'
const AtMention = {

View File

@@ -48,10 +48,12 @@
</Actions>
</h5>
<!-- eslint-disable vue/no-v-html -->
<div v-if="!descriptionEditing && hasDescription"
id="description-preview"
@click="clickedPreview"
v-html="renderedDescription" />
<!-- eslint-enable -->
<p v-else-if="!descriptionEditing" class="placeholder" @click="showEditor()">
{{ t('deck', 'Write a description ') }}
</p>
@@ -78,7 +80,7 @@
import MarkdownIt from 'markdown-it'
import MarkdownItTaskLists from 'markdown-it-task-lists'
import MarkdownItLinkAttributes from 'markdown-it-link-attributes'
import AttachmentList from './AttachmentList'
import AttachmentList from './AttachmentList.vue'
import { Actions, ActionButton, Modal } from '@nextcloud/vue'
import { formatFileSize } from '@nextcloud/files'
import { generateUrl } from '@nextcloud/router'

View File

@@ -49,8 +49,8 @@
</div>
</template>
<script>
import AvatarList from './AvatarList'
import CardMenu from './CardMenu'
import AvatarList from './AvatarList.vue'
import CardMenu from './CardMenu.vue'
import TextIcon from 'vue-material-design-icons/Text.vue'
import AttachmentIcon from 'vue-material-design-icons/Paperclip.vue'
import CheckmarkIcon from 'vue-material-design-icons/CheckboxMarked.vue'

View File

@@ -79,12 +79,12 @@
<script>
import ClickOutside from 'vue-click-outside'
import { mapState, mapGetters } from 'vuex'
import CardBadges from './CardBadges'
import Color from '../../mixins/color'
import labelStyle from '../../mixins/labelStyle'
import AttachmentDragAndDrop from '../AttachmentDragAndDrop'
import CardMenu from './CardMenu'
import DueDate from './badges/DueDate'
import CardBadges from './CardBadges.vue'
import Color from '../../mixins/color.js'
import labelStyle from '../../mixins/labelStyle.js'
import AttachmentDragAndDrop from '../AttachmentDragAndDrop.vue'
import CardMenu from './CardMenu.vue'
import DueDate from './badges/DueDate.vue'
export default {
name: 'CardItem',

View File

@@ -96,8 +96,8 @@ import axios from '@nextcloud/axios'
import { mapGetters } from 'vuex'
import ClickOutside from 'vue-click-outside'
import { AppNavigation as AppNavigationVue, AppNavigationItem, AppNavigationSettings, Multiselect } from '@nextcloud/vue'
import AppNavigationAddBoard from './AppNavigationAddBoard'
import AppNavigationBoardCategory from './AppNavigationBoardCategory'
import AppNavigationAddBoard from './AppNavigationAddBoard.vue'
import AppNavigationBoardCategory from './AppNavigationBoardCategory.vue'
import { loadState } from '@nextcloud/initial-state'
import { generateOcsUrl } from '@nextcloud/router'
import { getCurrentUser } from '@nextcloud/auth'

View File

@@ -35,7 +35,7 @@
</template>
<script>
import AppNavigationBoard from './AppNavigationBoard'
import AppNavigationBoard from './AppNavigationBoard.vue'
import { AppNavigationItem } from '@nextcloud/vue'
export default {

View File

@@ -80,11 +80,11 @@
<script>
import Controls from '../Controls'
import CardItem from '../cards/CardItem'
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'
import GlobalSearchResults from '../search/GlobalSearchResults.vue'
const FILTER_UPCOMING = 'upcoming'

View File

@@ -52,13 +52,13 @@
</template>
<script>
import CardItem from '../cards/CardItem'
import CardItem from '../cards/CardItem.vue'
import { mapState } from 'vuex'
import axios from '@nextcloud/axios'
import { generateOcsUrl } from '@nextcloud/router'
import InfiniteLoading from 'vue-infinite-loading'
import RichText from '@juliushaertl/vue-richtext'
import Placeholder from './Placeholder'
import Placeholder from './Placeholder.vue'
import { Actions, ActionButton } from '@nextcloud/vue'
const createCancelToken = () => axios.CancelToken.source()

View File

@@ -23,8 +23,8 @@
import Vue from 'vue'
import './../css/collections.css'
import FileSharingPicker from './views/FileSharingPicker'
import { buildSelector } from './helpers/selector'
import FileSharingPicker from './views/FileSharingPicker.js'
import { buildSelector } from './helpers/selector.js'
// eslint-disable-next-line
__webpack_nonce__ = btoa(OC.requestToken);
@@ -44,7 +44,7 @@ window.addEventListener('DOMContentLoaded', () => {
window.OCP.Collaboration.registerType('deck', {
action: () => {
const BoardSelector = () => import('./BoardSelector')
const BoardSelector = () => import('./BoardSelector.vue')
return buildSelector(BoardSelector)
},
typeString: t('deck', 'Link to a board'),
@@ -53,7 +53,7 @@ window.addEventListener('DOMContentLoaded', () => {
window.OCP.Collaboration.registerType('deck-card', {
action: () => {
const CardSelector = () => import('./CardSelector')
const CardSelector = () => import('./CardSelector.vue')
return buildSelector(CardSelector)
},
typeString: t('deck', 'Link to a card'),

View File

@@ -21,9 +21,9 @@
*/
import Vue from 'vue'
import Vuex from 'vuex'
import Vuex, { Store } from 'vuex'
import overview from './store/overview'
import overview from './store/overview.js'
import './css/dashboard.scss'
@@ -33,7 +33,7 @@ Vue.use(Vuex)
const debug = process.env.NODE_ENV !== 'production'
const store = new Vuex.Store({
const store = new Store({
modules: {
overview,
},

View File

@@ -23,9 +23,9 @@
import Vue from 'vue'
import { generateUrl } from '@nextcloud/router'
import CardCreateDialog from './CardCreateDialog'
import { buildSelector } from './helpers/selector'
import './init-collections'
import CardCreateDialog from './CardCreateDialog.vue'
import { buildSelector } from './helpers/selector.js'
import './init-collections.js'
// eslint-disable-next-line
__webpack_nonce__ = btoa(OC.requestToken);

View File

@@ -20,9 +20,6 @@
*
*/
import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store/main'
import { sync } from 'vuex-router-sync'
import { translate, translatePlural } from '@nextcloud/l10n'
import { generateFilePath } from '@nextcloud/router'
@@ -30,7 +27,10 @@ import { showError } from '@nextcloud/dialogs'
import { subscribe } from '@nextcloud/event-bus'
import { Tooltip } from '@nextcloud/vue'
import ClickOutside from 'vue-click-outside'
import './models'
import App from './App.vue'
import router from './router.js'
import store from './store/main.js'
import './models/index.js'
// the server snap.js conflicts with vertical scrolling so we disable it
document.body.setAttribute('data-snap-ignore', 'true')

View File

@@ -20,7 +20,7 @@
*
*/
import Color from './color'
import Color from './color.js'
export default {
mixins: [Color],

View File

@@ -23,13 +23,13 @@
import Vue from 'vue'
import Router from 'vue-router'
import { generateUrl } from '@nextcloud/router'
import { BOARD_FILTERS } from './store/main'
import Boards from './components/boards/Boards'
import Board from './components/board/Board'
import Sidebar from './components/Sidebar'
import BoardSidebar from './components/board/BoardSidebar'
import CardSidebar from './components/card/CardSidebar'
import Overview from './components/overview/Overview'
import { BOARD_FILTERS } from './store/main.js'
import Boards from './components/boards/Boards.vue'
import Board from './components/board/Board.vue'
import Sidebar from './components/Sidebar.vue'
import BoardSidebar from './components/board/BoardSidebar.vue'
import CardSidebar from './components/card/CardSidebar.vue'
import Overview from './components/overview/Overview.vue'
Vue.use(Router)

View File

@@ -22,7 +22,7 @@
import axios from '@nextcloud/axios'
import { generateUrl } from '@nextcloud/router'
import './../models'
import './../models/index.js'
/**
* This class handles all the api communication with the Deck backend.

View File

@@ -22,7 +22,7 @@
import axios from '@nextcloud/axios'
import { generateUrl } from '@nextcloud/router'
import './../models'
import './../models/index.js'
export class StackApi {

View File

@@ -20,7 +20,7 @@
*
*/
import { AttachmentApi } from './../services/AttachmentApi'
import { AttachmentApi } from './../services/AttachmentApi.js'
import Vue from 'vue'
const apiClient = new AttachmentApi()
@@ -84,6 +84,7 @@ export default {
async fetchAttachments({ commit }, cardId) {
const attachments = await apiClient.fetchAttachments(cardId)
commit('createAttachments', { cardId, attachments })
commit('cardSetAttachmentCount', { cardId, count: attachments.length })
},
async createAttachment({ commit }, { cardId, formData, onUploadProgress }) {

View File

@@ -20,7 +20,7 @@
*
*/
import { CardApi } from './../services/CardApi'
import { CardApi } from './../services/CardApi.js'
import moment from 'moment'
import Vue from 'vue'
@@ -252,6 +252,12 @@ export default {
Vue.set(state.cards[existingIndex], 'lastModified', Date.now() / 1000)
}
},
cardSetAttachmentCount(state, { cardId, count }) {
const existingIndex = state.cards.findIndex(_card => _card.id === cardId)
if (existingIndex !== -1) {
Vue.set(state.cards[existingIndex], 'attachmentCount', count)
}
},
cardIncreaseAttachmentCount(state, cardId) {
const existingIndex = state.cards.findIndex(_card => _card.id === cardId)
if (existingIndex !== -1) {

View File

@@ -20,7 +20,7 @@
*
*/
import { CommentApi } from '../services/CommentApi'
import { CommentApi } from '../services/CommentApi.js'
import Vue from 'vue'
const apiClient = new CommentApi()

View File

@@ -24,17 +24,17 @@ import 'url-search-params-polyfill'
import { loadState } from '@nextcloud/initial-state'
import Vue from 'vue'
import Vuex from 'vuex'
import Vuex, { Store } from 'vuex'
import axios from '@nextcloud/axios'
import { generateOcsUrl, generateUrl } from '@nextcloud/router'
import { BoardApi } from '../services/BoardApi'
import actions from './actions'
import stack from './stack'
import card from './card'
import comment from './comment'
import trashbin from './trashbin'
import attachment from './attachment'
import overview from './overview'
import { BoardApi } from '../services/BoardApi.js'
import actions from './actions.js'
import stack from './stack.js'
import card from './card.js'
import comment from './comment.js'
import trashbin from './trashbin.js'
import attachment from './attachment.js'
import overview from './overview.js'
Vue.use(Vuex)
const apiClient = new BoardApi()
@@ -46,7 +46,7 @@ export const BOARD_FILTERS = {
SHARED: 'shared',
}
export default new Vuex.Store({
export default new Store({
modules: {
actions,
stack,

View File

@@ -22,7 +22,7 @@
import Vue from 'vue'
import Vuex from 'vuex'
import { OverviewApi } from '../services/OverviewApi'
import { OverviewApi } from '../services/OverviewApi.js'
Vue.use(Vuex)
const apiClient = new OverviewApi()

View File

@@ -21,8 +21,8 @@
*/
import Vue from 'vue'
import { StackApi } from './../services/StackApi'
import applyOrderToArray from './../helpers/applyOrderToArray'
import { StackApi } from './../services/StackApi.js'
import applyOrderToArray from './../helpers/applyOrderToArray.js'
const apiClient = new StackApi()

View File

@@ -20,8 +20,8 @@
*
*/
import { StackApi } from '../services/StackApi'
import { CardApi } from '../services/CardApi'
import { StackApi } from '../services/StackApi.js'
import { CardApi } from '../services/CardApi.js'
const stackApi = new StackApi()
const cardApi = new CardApi()

View File

@@ -59,10 +59,10 @@
<script>
import { DashboardWidget } from '@nextcloud/vue-dashboard'
import { mapGetters } from 'vuex'
import labelStyle from './../mixins/labelStyle'
import DueDate from '../components/cards/badges/DueDate'
import labelStyle from './../mixins/labelStyle.js'
import DueDate from '../components/cards/badges/DueDate.vue'
import { generateUrl } from '@nextcloud/router'
import CardCreateDialog from '../CardCreateDialog'
import CardCreateDialog from '../CardCreateDialog.vue'
export default {
name: 'Dashboard',

View File

@@ -21,7 +21,7 @@
*/
import Vue from 'vue'
import { createShare } from '../services/SharingApi'
import { createShare } from '../services/SharingApi.js'
export default {
icon: 'icon-deck',
@@ -33,7 +33,7 @@ export default {
container.id = 'deck-board-select'
const body = document.getElementById('body-user')
body.append(container)
const CardSelector = () => import('./../CardSelector')
const CardSelector = () => import('./../CardSelector.vue')
const ComponentVM = new Vue({
render: (h) => h(CardSelector, {
title: t('deck', 'Share {file} with a Deck card', { file: decodeURIComponent(self.fileInfo.name) }),

View File

@@ -25,6 +25,7 @@ namespace OCA\Deck\Service;
use OCA\Deck\Activity\ActivityManager;
use OCA\Deck\AppInfo\Application;
use OCA\Deck\Cache\AttachmentCacheHelper;
use OCA\Deck\Db\Acl;
use OCA\Deck\Db\Attachment;
use OCA\Deck\Db\AttachmentMapper;
@@ -35,8 +36,6 @@ use OCA\Deck\NoPermissionException;
use OCA\Deck\NotFoundException;
use OCP\AppFramework\Http\Response;
use OCP\AppFramework\IAppContainer;
use OCP\ICache;
use OCP\ICacheFactory;
use OCP\IL10N;
use PHPUnit\Framework\MockObject\MockObject;
use Test\TestCase;
@@ -67,10 +66,11 @@ class AttachmentServiceTest extends TestCase {
private $cardMapper;
/** @var PermissionService|MockObject */
private $permissionService;
/** @var string */
private $userId = 'admin';
/** @var Application|MockObject */
private $application;
private $cacheFactory;
private $attachmentCacheHelper;
/** @var AttachmentService */
private $attachmentService;
/** @var MockObject */
@@ -78,8 +78,6 @@ class AttachmentServiceTest extends TestCase {
/** @var ActivityManager */
private $activityManager;
private $appContainer;
/** ICache */
private $cache;
/** @var IL10N */
private $l10n;
/** @var ChangeHelper */
@@ -104,12 +102,9 @@ class AttachmentServiceTest extends TestCase {
$this->cardMapper = $this->createMock(CardMapper::class);
$this->permissionService = $this->createMock(PermissionService::class);
$this->application = $this->createMock(Application::class);
$this->cacheFactory = $this->createMock(ICacheFactory::class);
$this->attachmentCacheHelper = $this->createMock(AttachmentCacheHelper::class);
$this->activityManager = $this->createMock(ActivityManager::class);
$this->cache = $this->createMock(ICache::class);
$this->cacheFactory->expects($this->any())->method('createDistributed')->willReturn($this->cache);
$this->appContainer->expects($this->exactly(2))
->method('query')
->withConsecutive(
@@ -128,7 +123,17 @@ class AttachmentServiceTest extends TestCase {
$this->l10n = $this->createMock(IL10N::class);
$this->changeHelper = $this->createMock(ChangeHelper::class);
$this->attachmentService = new AttachmentService($this->attachmentMapper, $this->cardMapper, $this->changeHelper, $this->permissionService, $this->application, $this->cacheFactory, $this->userId, $this->l10n, $this->activityManager);
$this->attachmentService = new AttachmentService(
$this->attachmentMapper,
$this->cardMapper,
$this->changeHelper,
$this->permissionService,
$this->application,
$this->attachmentCacheHelper,
$this->userId,
$this->l10n,
$this->activityManager
);
}
public function testRegisterAttachmentService() {
@@ -153,7 +158,7 @@ class AttachmentServiceTest extends TestCase {
$application->expects($this->any())
->method('getContainer')
->willReturn($appContainer);
$attachmentService = new AttachmentService($this->attachmentMapper, $this->cardMapper, $this->changeHelper, $this->permissionService, $application, $this->cacheFactory, $this->userId, $this->l10n, $this->activityManager);
$attachmentService = new AttachmentService($this->attachmentMapper, $this->cardMapper, $this->changeHelper, $this->permissionService, $application, $this->attachmentCacheHelper, $this->userId, $this->l10n, $this->activityManager);
$attachmentService->registerAttachmentService('custom', MyAttachmentService::class);
$this->assertEquals($fileServiceMock, $attachmentService->getService('deck_file'));
$this->assertEquals(MyAttachmentService::class, get_class($attachmentService->getService('custom')));
@@ -183,7 +188,7 @@ class AttachmentServiceTest extends TestCase {
->method('getContainer')
->willReturn($appContainer);
$attachmentService = new AttachmentService($this->attachmentMapper, $this->cardMapper, $this->changeHelper, $this->permissionService, $application, $this->cacheFactory, $this->userId, $this->l10n, $this->activityManager);
$attachmentService = new AttachmentService($this->attachmentMapper, $this->cardMapper, $this->changeHelper, $this->permissionService, $application, $this->attachmentCacheHelper, $this->userId, $this->l10n, $this->activityManager);
$attachmentService->registerAttachmentService('custom', MyAttachmentService::class);
$attachmentService->getService('deck_file_invalid');
}
@@ -262,14 +267,14 @@ class AttachmentServiceTest extends TestCase {
}
public function testCount() {
$this->cache->expects($this->once())->method('get')->with('card-123')->willReturn(null);
$this->attachmentCacheHelper->expects($this->once())->method('getAttachmentCount')->with(123)->willReturn(null);
$this->attachmentMapper->expects($this->once())->method('findAll')->willReturn([1,2,3,4]);
$this->cache->expects($this->once())->method('set')->with('card-123', 4)->willReturn(null);
$this->attachmentCacheHelper->expects($this->once())->method('setAttachmentCount')->with(123, 4);
$this->assertEquals(4, $this->attachmentService->count(123));
}
public function testCountCacheHit() {
$this->cache->expects($this->once())->method('get')->with('card-123')->willReturn(4);
$this->attachmentCacheHelper->expects($this->once())->method('getAttachmentCount')->with(123)->willReturn(4);
$this->assertEquals(4, $this->attachmentService->count(123));
}
@@ -277,7 +282,7 @@ class AttachmentServiceTest extends TestCase {
$attachment = $this->createAttachment('deck_file', 'file_name.jpg');
$expected = $this->createAttachment('deck_file', 'file_name.jpg');
$this->mockPermission(Acl::PERMISSION_EDIT);
$this->cache->expects($this->once())->method('clear')->with('card-123');
$this->attachmentCacheHelper->expects($this->once())->method('clearAttachmentCount')->with(123);
$this->attachmentServiceImpl->expects($this->once())
->method('create');
$this->attachmentMapper->expects($this->once())
@@ -330,7 +335,7 @@ class AttachmentServiceTest extends TestCase {
$attachment = $this->createAttachment('deck_file', 'file_name.jpg');
$expected = $this->createAttachment('deck_file', 'file_name.jpg');
$this->mockPermission(Acl::PERMISSION_EDIT);
$this->cache->expects($this->once())->method('clear')->with('card-123');
$this->attachmentCacheHelper->expects($this->once())->method('clearAttachmentCount')->with(1);
$this->attachmentMapper->expects($this->once())
->method('find')
->with(1)
@@ -357,7 +362,7 @@ class AttachmentServiceTest extends TestCase {
$attachment = $this->createAttachment('deck_file', 'file_name.jpg');
$expected = $this->createAttachment('deck_file', 'file_name.jpg');
$this->mockPermission(Acl::PERMISSION_EDIT);
$this->cache->expects($this->once())->method('clear')->with('card-123');
$this->attachmentCacheHelper->expects($this->once())->method('clearAttachmentCount')->with(1);
$this->attachmentMapper->expects($this->once())
->method('find')
->with(1)
@@ -378,7 +383,7 @@ class AttachmentServiceTest extends TestCase {
$attachment = $this->createAttachment('deck_file', 'file_name.jpg');
$expected = $this->createAttachment('deck_file', 'file_name.jpg');
$this->mockPermission(Acl::PERMISSION_EDIT);
$this->cache->expects($this->once())->method('clear')->with('card-123');
$this->attachmentCacheHelper->expects($this->once())->method('clearAttachmentCount')->with(1);
$this->attachmentMapper->expects($this->once())
->method('find')
->with(1)
@@ -403,7 +408,7 @@ class AttachmentServiceTest extends TestCase {
$attachment = $this->createAttachment('deck_file', 'file_name.jpg');
$expected = $this->createAttachment('deck_file', 'file_name.jpg');
$this->mockPermission(Acl::PERMISSION_EDIT);
$this->cache->expects($this->once())->method('clear')->with('card-123');
$this->attachmentCacheHelper->expects($this->once())->method('clearAttachmentCount')->with(1);
$this->attachmentMapper->expects($this->once())
->method('find')
->with(1)
@@ -424,7 +429,7 @@ class AttachmentServiceTest extends TestCase {
$attachment = $this->createAttachment('deck_file', 'file_name.jpg');
$expected = $this->createAttachment('deck_file', 'file_name.jpg');
$this->mockPermission(Acl::PERMISSION_EDIT);
$this->cache->expects($this->once())->method('clear')->with('card-123');
$this->attachmentCacheHelper->expects($this->once())->method('clearAttachmentCount')->with(1);
$this->attachmentMapper->expects($this->once())
->method('find')
->with(1)