diff --git a/lib/Controller/FileController.php b/lib/Controller/FileController.php index aeea8657ea..99b7dd3cf6 100644 --- a/lib/Controller/FileController.php +++ b/lib/Controller/FileController.php @@ -26,6 +26,7 @@ use OCA\Files_Sharing\SharedStorage; use OCA\Libresign\AppInfo\Application; +use OCA\Libresign\Db\File as FileEntity; use OCA\Libresign\Db\SignRequestMapper; use OCA\Libresign\Exception\LibresignException; use OCA\Libresign\Helper\JSActions; @@ -35,6 +36,7 @@ use OCA\Libresign\Service\AccountService; use OCA\Libresign\Service\FileService; use OCA\Libresign\Service\IdentifyMethodService; +use OCA\Libresign\Service\RequestSignatureService; use OCA\Libresign\Service\SessionService; use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Http; @@ -75,6 +77,7 @@ public function __construct( private SessionService $sessionService, private SignRequestMapper $signRequestMapper, private IdentifyMethodService $identifyMethodService, + private RequestSignatureService $requestSignatureService, private AccountService $accountService, private IRootFolder $root, private IPreview $preview, @@ -208,9 +211,13 @@ public function validate(?string $type = null, $identifier = null): DataResponse * * @param string|null $signer_uuid Signer UUID * @param string|null $nodeId The nodeId (also called fileId). Is the id of a file at Nextcloud - * @param int|null $status Status could be one of 0 = draft, 1 = able to sign, 2 = partial signed, 3 = signed, 4 = deleted. + * @param list|null $status Status could be none or many of 0 = draft, 1 = able to sign, 2 = partial signed, 3 = signed, 4 = deleted. * @param int|null $page the number of page to return * @param int|null $length Total of elements to return + * @param int|null $start Start date of signature request (UNIX timestamp) + * @param int|null $end End date of signature request (UNIX timestamp) + * @param string|null $sortBy Name of the column to sort by + * @param string|null $sortDirection Ascending or descending order * @return DataResponse * * 200: OK @@ -223,16 +230,26 @@ public function list( ?int $length = null, ?string $signer_uuid = null, ?string $nodeId = null, - ?int $status = null, + ?array $status = null, + ?int $start = null, + ?int $end = null, + ?string $sortBy = null, + ?string $sortDirection = null, ): DataResponse { $filter = array_filter([ 'signer_uuid' => $signer_uuid, 'nodeId' => $nodeId, 'status' => $status, + 'start' => $start, + 'end' => $end, ], static function ($var) { return $var !== null; }); + $sort = [ + 'sortBy' => $sortBy, + 'sortDirection' => $sortDirection, + ]; $return = $this->fileService ->setMe($this->userSession->getUser()) - ->listAssociatedFilesOfSignFlow($page, $length, $filter); + ->listAssociatedFilesOfSignFlow($page, $length, $filter, $sort); return new DataResponse($return, Http::STATUS_OK); } @@ -372,6 +389,15 @@ public function save(array $file, string $name = '', array $settings = []): Data 'file' => $file, 'settings' => $settings ]); + $data = [ + 'file' => [ + 'fileNode' => $node, + ], + 'name' => $name, + 'userManager' => $this->userSession->getUser(), + 'status' => FileEntity::STATUS_DRAFT, + ]; + $file = $this->requestSignatureService->save($data); return new DataResponse( [ @@ -393,4 +419,46 @@ public function save(array $file, string $name = '', array $settings = []): Data ); } } + + /** + * Delete File + * + * This will delete the file and all data + * + * @param integer $fileId Node id of a Nextcloud file + * @return DataResponse|DataResponse|DataResponse + * + * 200: OK + * 401: Failed + * 422: Failed + */ + #[NoAdminRequired] + #[NoCSRFRequired] + #[RequireManager] + #[ApiRoute(verb: 'DELETE', url: '/api/{apiVersion}/file/file_id/{fileId}', requirements: ['apiVersion' => '(v1)'])] + public function deleteAllRequestSignatureUsingFileId(int $fileId): DataResponse { + try { + $data = [ + 'userManager' => $this->userSession->getUser(), + 'file' => [ + 'fileId' => $fileId + ] + ]; + $this->validateHelper->validateExistingFile($data); + $this->fileService->delete($fileId); + } catch (\Throwable $th) { + return new DataResponse( + [ + 'message' => $th->getMessage(), + ], + Http::STATUS_UNAUTHORIZED + ); + } + return new DataResponse( + [ + 'message' => $this->l10n->t('Success') + ], + Http::STATUS_OK + ); + } } diff --git a/lib/Db/AccountFileMapper.php b/lib/Db/AccountFileMapper.php index 3428c8e811..192ec131b3 100644 --- a/lib/Db/AccountFileMapper.php +++ b/lib/Db/AccountFileMapper.php @@ -167,7 +167,7 @@ private function getUserAccountFile(array $filter = []): Pagination { $qb->setMaxResults($filter['length']); } - $pagination = new Pagination($qb); + $pagination = new Pagination($qb, $this->urlGenerator); return $pagination; } diff --git a/lib/Db/SignRequestMapper.php b/lib/Db/SignRequestMapper.php index 0a2a0ccb1f..007cb729de 100644 --- a/lib/Db/SignRequestMapper.php +++ b/lib/Db/SignRequestMapper.php @@ -362,11 +362,12 @@ public function getFilesAssociatedFilesWithMeFormatted( array $filter, ?int $page = null, ?int $length = null, + ?array $sort = [], ): array { $filter['email'] = $user->getEMailAddress(); $filter['length'] = $length; $filter['page'] = $page; - $pagination = $this->getFilesAssociatedFilesWithMeStmt($user->getUID(), $filter); + $pagination = $this->getFilesAssociatedFilesWithMeStmt($user->getUID(), $filter, $sort); $pagination->setMaxPerPage($length); $pagination->setCurrentPage($page); $currentPageResults = $pagination->getCurrentPageResults(); @@ -505,7 +506,17 @@ private function getFilesAssociatedFilesWithMeQueryBuilder(string $userId, ?arra } if (!empty($filter['status'])) { $qb->andWhere( - $qb->expr()->eq('f.status', $qb->createNamedParameter($filter['status'], IQueryBuilder::PARAM_INT)) + $qb->expr()->in('f.status', $qb->createNamedParameter($filter['status'], IQueryBuilder::PARAM_INT_ARRAY)) + ); + } + if (!empty($filter['start'])) { + $qb->andWhere( + $qb->expr()->gte('f.created_at', $qb->createNamedParameter($filter['start'], IQueryBuilder::PARAM_INT)) + ); + } + if (!empty($filter['end'])) { + $qb->andWhere( + $qb->expr()->lte('f.created_at', $qb->createNamedParameter($filter['end'], IQueryBuilder::PARAM_INT)) ); } if (isset($filter['length']) && isset($filter['page'])) { @@ -516,7 +527,11 @@ private function getFilesAssociatedFilesWithMeQueryBuilder(string $userId, ?arra return $qb; } - private function getFilesAssociatedFilesWithMeStmt(string $userId, ?array $filter = []): Pagination { + private function getFilesAssociatedFilesWithMeStmt( + string $userId, + ?array $filter = [], + ?array $sort = [], + ): Pagination { $qb = $this->getFilesAssociatedFilesWithMeQueryBuilder($userId, $filter); $qb->select( 'f.id', @@ -527,6 +542,12 @@ private function getFilesAssociatedFilesWithMeStmt(string $userId, ?array $filte 'f.status', 'f.metadata', ); + if (!empty($sort) && in_array($sort['sortBy'], ['name', 'status', 'created_at'])) { + $qb->orderBy( + $qb->func()->lower('f.' . $sort['sortBy']), + $sort['sortDirection'] == 'asc' ? 'asc' : 'desc' + ); + } $qb->selectAlias('f.created_at', 'request_date'); $countQueryBuilderModifier = function (IQueryBuilder $qb): int { @@ -538,7 +559,7 @@ private function getFilesAssociatedFilesWithMeStmt(string $userId, ?array $filte return (int)$qb->executeQuery()->fetchOne(); }; - $pagination = new Pagination($qb); + $pagination = new Pagination($qb, $this->urlGenerator); return $pagination; } diff --git a/lib/Helper/Pagination.php b/lib/Helper/Pagination.php index b3a4129297..5e1f87db8f 100644 --- a/lib/Helper/Pagination.php +++ b/lib/Helper/Pagination.php @@ -26,13 +26,14 @@ use OCA\Libresign\Db\PagerFantaQueryAdapter; use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\IURLGenerator; use Pagerfanta\Pagerfanta; class Pagination extends Pagerfanta { - /** @var string */ - private $rootPath; + private string $routeName; public function __construct( IQueryBuilder $queryBuilder, + private IURLGenerator $urlGenerator, ) { $adapter = new PagerFantaQueryAdapter($queryBuilder); parent::__construct($adapter); @@ -41,27 +42,59 @@ public function __construct( /** * @return static */ - public function setRootPath(string $rootPath = ''): self { - $this->rootPath = $rootPath; + public function setRouteName(string $routeName = ''): self { + $this->routeName = $routeName; return $this; } - public function getPagination(?int $page, ?int $length): array { + public function getPagination(int $page, int $length, array $filter = []): array { $this->setMaxPerPage($length); - $pagination['total'] = $this->count(); - if ($pagination['total'] > $length) { - $pagination['current'] = $this->rootPath . '?page=' . $page . '&length=' . $length; - $pagination['next'] = $this->hasNextPage() ? $this->rootPath . '?page=' . $this->getNextPage() . '&length=' . $length : null; - $pagination['prev'] = $this->hasPreviousPage() ? $this->rootPath . '?page=' . $this->getPreviousPage() . '&length=' . $length : null; - $pagination['last'] = $this->hasNextPage() ? $this->rootPath . '?page=' . $this->getNbPages() . '&length=' . $length : null; - $pagination['first'] = $this->hasPreviousPage() ? $this->rootPath . '?page=1&length=' . $length : null; - } else { - $pagination['current'] = null; - $pagination['next'] = null; - $pagination['prev'] = null; - $pagination['last'] = null; - $pagination['first'] = null; + $total = $this->count(); + if ($total > $length) { + return [ + 'total' => $total, + 'current' => $this->linkToRoute(true, $page, $length, $filter), + 'next' => $this->linkToRoute($this->hasNextPage(), 'getNextPage', $length, $filter), + 'prev' => $this->linkToRoute($this->hasPreviousPage(), 'getPreviousPage', $length, $filter), + 'last' => $this->linkToRoute($this->hasNextPage(), 'getNbPages', $length, $filter), + 'first' => $this->linkToRoute($this->hasPreviousPage(), 1, $length, $filter), + ]; } - return $pagination; + return [ + 'total' => $total, + 'current' => null, + 'next' => null, + 'prev' => null, + 'last' => null, + 'first' => null, + ]; + } + + private function linkToRoute(bool $condition, int|string $page, int $length, array $filter): ?string { + if (!$condition) { + return null; + } + if (is_string($page)) { + $page = $this->$page(); + } + $url = $this->urlGenerator->linkToRouteAbsolute( + $this->routeName, + array_merge(['page' => $page, 'length' => $length, 'apiVersion' => 'v1'], $filter) + ); + $url = $this->sortParameters($url); + return $url; + } + + /** + * This is necessary to fix problem at integration tests because the method linkToRoute change the order of parameters + */ + private function sortParameters(?string $url): ?string { + if (!$url) { + return $url; + } + parse_str(parse_url($url, PHP_URL_QUERY), $query); + ksort($query); + $url = strtok($url, '?') . '?' . http_build_query($query); + return $url; } } diff --git a/lib/Service/AccountFileService.php b/lib/Service/AccountFileService.php index 48e4afc9a3..38321e728f 100644 --- a/lib/Service/AccountFileService.php +++ b/lib/Service/AccountFileService.php @@ -65,10 +65,10 @@ public function accountFileList(array $filter, ?int $page = null, ?int $length = $page = $page ?? 1; $length = $length ?? (int)$this->appConfig->getAppValue('length_of_page', '100'); $data = $this->accountFileMapper->accountFileList($filter, $page, $length); - $data['pagination']->setRootPath('/file/list'); + $data['pagination']->setRouteName('ocs.libresign.File.list'); return [ 'data' => $data['data'], - 'pagination' => $data['pagination']->getPagination($page, $length) + 'pagination' => $data['pagination']->getPagination($page, $length, $filter) ]; } } diff --git a/lib/Service/FileService.php b/lib/Service/FileService.php index 78abfdf9f1..83a7cf4412 100644 --- a/lib/Service/FileService.php +++ b/lib/Service/FileService.php @@ -448,7 +448,12 @@ public function setFileByPath(string $path): self { * * @psalm-return array{data: array, pagination: array} */ - public function listAssociatedFilesOfSignFlow($page = null, $length = null, array $filter = []): array { + public function listAssociatedFilesOfSignFlow( + $page = null, + $length = null, + array $filter = [], + array $sort = [], + ): array { $page = $page ?? 1; $length = $length ?? (int)$this->appConfig->getAppValue('length_of_page', '100'); @@ -457,6 +462,7 @@ public function listAssociatedFilesOfSignFlow($page = null, $length = null, arra $filter, $page, $length, + $sort, ); $signers = $this->signRequestMapper->getByMultipleFileId(array_column($return['data'], 'id')); @@ -464,10 +470,10 @@ public function listAssociatedFilesOfSignFlow($page = null, $length = null, arra $visibleElements = $this->signRequestMapper->getVisibleElementsFromSigners($signers); $return['data'] = $this->associateAllAndFormat($this->me, $return['data'], $signers, $identifyMethods, $visibleElements); - $return['pagination']->setRootPath('/file/list'); + $return['pagination']->setRouteName('ocs.libresign.File.list'); return [ 'data' => $return['data'], - 'pagination' => $return['pagination']->getPagination($page, $length) + 'pagination' => $return['pagination']->getPagination($page, $length, $filter) ]; } @@ -601,4 +607,20 @@ public function getMyLibresignFile(int $nodeId): File { ], ); } + + public function delete(int $fileId): void { + $file = $this->fileMapper->getByFileId($fileId); + $this->fileElementService->deleteVisibleElements($file->getId()); + $list = $this->signRequestMapper->getByFileId($file->getId()); + foreach ($list as $signRequest) { + $this->signRequestMapper->delete($signRequest); + } + $this->fileMapper->delete($file); + if ($file->getSignedNodeId()) { + $signedNextcloudFile = $this->folderService->getFileById($file->getSignedNodeId()); + $signedNextcloudFile->delete(); + } + $nextcloudFile = $this->folderService->getFileById($fileId); + $nextcloudFile->delete(); + } } diff --git a/openapi-full.json b/openapi-full.json index 7a5298e3b1..fad3f76592 100644 --- a/openapi-full.json +++ b/openapi-full.json @@ -1128,6 +1128,48 @@ } } }, + "/index.php/apps/libresign/p/sign/{uuid}/pdf": { + "get": { + "operationId": "page-sign-pdf", + "summary": "Sign page to authenticated signer", + "description": "The path is used only by frontend", + "tags": [ + "page" + ], + "security": [ + {}, + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "Sign request uuid", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/html": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, "/index.php/apps/libresign/p/sign/{uuid}": { "get": { "operationId": "page-sign", @@ -3695,9 +3737,32 @@ } }, { - "name": "status", + "name": "status[]", + "in": "query", + "description": "Status could be none or many of 0 = draft, 1 = able to sign, 2 = partial signed, 3 = signed, 4 = deleted.", + "schema": { + "type": "array", + "nullable": true, + "items": { + "type": "integer", + "format": "int64" + } + } + }, + { + "name": "start", + "in": "query", + "description": "Start date of signature request (UNIX timestamp)", + "schema": { + "type": "integer", + "format": "int64", + "nullable": true + } + }, + { + "name": "end", "in": "query", - "description": "Status could be one of 0 = draft, 1 = able to sign, 2 = partial signed, 3 = signed, 4 = deleted.", + "description": "End date of signature request (UNIX timestamp)", "schema": { "type": "integer", "format": "int64", diff --git a/openapi.json b/openapi.json index ebf9a8d844..fde54c2766 100644 --- a/openapi.json +++ b/openapi.json @@ -1032,6 +1032,48 @@ } } }, + "/index.php/apps/libresign/p/sign/{uuid}/pdf": { + "get": { + "operationId": "page-sign-pdf", + "summary": "Sign page to authenticated signer", + "description": "The path is used only by frontend", + "tags": [ + "page" + ], + "security": [ + {}, + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "Sign request uuid", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/html": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, "/index.php/apps/libresign/p/sign/{uuid}": { "get": { "operationId": "page-sign", @@ -3599,9 +3641,32 @@ } }, { - "name": "status", + "name": "status[]", + "in": "query", + "description": "Status could be none or many of 0 = draft, 1 = able to sign, 2 = partial signed, 3 = signed, 4 = deleted.", + "schema": { + "type": "array", + "nullable": true, + "items": { + "type": "integer", + "format": "int64" + } + } + }, + { + "name": "start", + "in": "query", + "description": "Start date of signature request (UNIX timestamp)", + "schema": { + "type": "integer", + "format": "int64", + "nullable": true + } + }, + { + "name": "end", "in": "query", - "description": "Status could be one of 0 = draft, 1 = able to sign, 2 = partial signed, 3 = signed, 4 = deleted.", + "description": "End date of signature request (UNIX timestamp)", "schema": { "type": "integer", "format": "int64", diff --git a/package-lock.json b/package-lock.json index 39815131ab..fba9baaf9c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,8 @@ "@fontsource/dancing-script": "^5.1.0", "@libresign/vue-pdf-editor": "^1.3.7", "@marionebl/option": "^1.0.8", + "@mdi/js": "^7.4.47", + "@mdi/svg": "^7.4.47", "@nextcloud/auth": "^2.4.0", "@nextcloud/axios": "^2.5.1", "@nextcloud/dialogs": "^6.0.1", @@ -26,7 +28,9 @@ "@nextcloud/router": "^3.0.1", "@nextcloud/vue": "^8.19.0", "blueimp-md5": "^2.19.0", + "copy-webpack-plugin": "^12.0.2", "crypto-js": "^4.2.0", + "debounce": "^2.2.0", "js-confetti": "^0.12.0", "pinia": "^2.2.6", "v-perfect-signature": "^1.4.0", diff --git a/package.json b/package.json index f9968c75d0..6df0422aa0 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,8 @@ "@fontsource/dancing-script": "^5.1.0", "@libresign/vue-pdf-editor": "^1.3.7", "@marionebl/option": "^1.0.8", + "@mdi/js": "^7.4.47", + "@mdi/svg": "^7.4.47", "@nextcloud/auth": "^2.4.0", "@nextcloud/axios": "^2.5.1", "@nextcloud/dialogs": "^6.0.1", @@ -37,7 +39,9 @@ "@nextcloud/router": "^3.0.1", "@nextcloud/vue": "^8.19.0", "blueimp-md5": "^2.19.0", + "copy-webpack-plugin": "^12.0.2", "crypto-js": "^4.2.0", + "debounce": "^2.2.0", "js-confetti": "^0.12.0", "pinia": "^2.2.6", "v-perfect-signature": "^1.4.0", diff --git a/src/Components/File/File.vue b/src/Components/File/File.vue index 4be34805bb..f5f8088a4e 100644 --- a/src/Components/File/File.vue +++ b/src/Components/File/File.vue @@ -11,10 +11,10 @@ @load="backgroundFailed = false">
-
- {{ filesStore.files[currentNodeId].statusText !== 'none' ? filesStore.files[currentNodeId].statusText : '' }} +
+ {{ filesStore.files.get(currentNodeId).statusText !== 'none' ? filesStore.files.get(currentNodeId).statusText : '' }}
-

{{ filesStore.files[currentNodeId].name }}

+

{{ filesStore.files.get(currentNodeId).name }}

@@ -60,7 +60,7 @@ export default { return null } let previewUrl = '' - if (this.filesStore.files[this.currentNodeId]?.uuid?.length > 0) { + if (this.filesStore.files.get(this.currentNodeId)?.uuid?.length > 0) { previewUrl = generateOcsUrl('/apps/libresign/api/v1/file/thumbnail/{nodeId}', { nodeId: this.currentNodeId, }) diff --git a/src/Components/LeftSidebar/LeftSidebar.vue b/src/Components/LeftSidebar/LeftSidebar.vue index c3915253c5..3518ff3aac 100644 --- a/src/Components/LeftSidebar/LeftSidebar.vue +++ b/src/Components/LeftSidebar/LeftSidebar.vue @@ -31,8 +31,8 @@ -
- {{ t('libresign', 'Next') }} - @@ -49,7 +49,7 @@ {{ t('libresign', 'Sign') }} - {{ t('libresign', 'Validate') }} @@ -68,11 +68,9 @@ diff --git a/src/views/FilesList/FileEntry/FileEntryActions.vue b/src/views/FilesList/FileEntry/FileEntryActions.vue new file mode 100644 index 0000000000..744ab69d55 --- /dev/null +++ b/src/views/FilesList/FileEntry/FileEntryActions.vue @@ -0,0 +1,230 @@ + + + + + + + + diff --git a/src/views/FilesList/FileEntry/FileEntryGrid.vue b/src/views/FilesList/FileEntry/FileEntryGrid.vue new file mode 100644 index 0000000000..e810debe8f --- /dev/null +++ b/src/views/FilesList/FileEntry/FileEntryGrid.vue @@ -0,0 +1,72 @@ + + + + diff --git a/src/views/FilesList/FileEntry/FileEntryMixin.js b/src/views/FilesList/FileEntry/FileEntryMixin.js new file mode 100644 index 0000000000..8cbcbd6985 --- /dev/null +++ b/src/views/FilesList/FileEntry/FileEntryMixin.js @@ -0,0 +1,75 @@ +/** + * SPDX-FileCopyrightText: 2021 LibreCode coop and LibreCode contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +export default { + props: { + source: { + type: Object, + required: true, + }, + loading: { + type: Boolean, + required: true, + }, + }, + computed: { + mtime() { + return Date.parse(this?.source?.request_date) + }, + + openedMenu: { + get() { + return this.actionsMenuStore.opened === this.source.nodeId + }, + set(opened) { + this.actionsMenuStore.opened = opened ? this.source.nodeId : null + }, + }, + + mtimeOpacity() { + const maxOpacityTime = 31 * 24 * 60 * 60 * 1000 // 31 days + + const mtime = this.mtime?.getTime?.() + if (!mtime) { + return {} + } + + // 1 = today, 0 = 31 days ago + const ratio = Math.round(Math.min(100, 100 * (maxOpacityTime - (Date.now() - mtime)) / maxOpacityTime)) + if (ratio < 0) { + return {} + } + return { + color: `color-mix(in srgb, var(--color-main-text) ${ratio}%, var(--color-text-maxcontrast))`, + } + }, + }, + methods: { + // Open the actions menu on right click + onRightClick(event) { + // If already opened, fallback to default browser + if (this.openedMenu) { + return + } + + // Reset any right menu position potentially set + const root = this.$el?.closest('main.app-content') + root.style.removeProperty('--mouse-pos-x') + root.style.removeProperty('--mouse-pos-y') + + this.actionsMenuStore.opened = this.source.nodeId + + // Prevent any browser defaults + event.preventDefault() + event.stopPropagation() + }, + + openDetailsIfAvailable(event) { + event.preventDefault() + event.stopPropagation() + this.filesStore.selectFile(this.source.nodeId) + }, + }, +} diff --git a/src/views/FilesList/FileEntry/FileEntryName.vue b/src/views/FilesList/FileEntry/FileEntryName.vue new file mode 100644 index 0000000000..bb2ddc4baa --- /dev/null +++ b/src/views/FilesList/FileEntry/FileEntryName.vue @@ -0,0 +1,74 @@ + + + + + + diff --git a/src/views/FilesList/FileEntry/FileEntryPreview.vue b/src/views/FilesList/FileEntry/FileEntryPreview.vue new file mode 100644 index 0000000000..d9774d7820 --- /dev/null +++ b/src/views/FilesList/FileEntry/FileEntryPreview.vue @@ -0,0 +1,90 @@ + + + + diff --git a/src/views/FilesList/FileEntry/FileEntryStatus.vue b/src/views/FilesList/FileEntry/FileEntryStatus.vue new file mode 100644 index 0000000000..349a445df1 --- /dev/null +++ b/src/views/FilesList/FileEntry/FileEntryStatus.vue @@ -0,0 +1,85 @@ + + + + + + diff --git a/src/views/FilesList/FileListFilter/FileListFilter.vue b/src/views/FilesList/FileListFilter/FileListFilter.vue new file mode 100644 index 0000000000..9fe6ecd121 --- /dev/null +++ b/src/views/FilesList/FileListFilter/FileListFilter.vue @@ -0,0 +1,62 @@ + + + + + + diff --git a/src/views/FilesList/FileListFilter/FileListFilterModified.vue b/src/views/FilesList/FileListFilter/FileListFilterModified.vue new file mode 100644 index 0000000000..2c6ef22cd3 --- /dev/null +++ b/src/views/FilesList/FileListFilter/FileListFilterModified.vue @@ -0,0 +1,141 @@ + + + + + + diff --git a/src/views/FilesList/FileListFilter/FileListFilterStatus.vue b/src/views/FilesList/FileListFilter/FileListFilterStatus.vue new file mode 100644 index 0000000000..6f6b2c2443 --- /dev/null +++ b/src/views/FilesList/FileListFilter/FileListFilterStatus.vue @@ -0,0 +1,137 @@ + + + + + + diff --git a/src/views/FilesList/FileListFilters.vue b/src/views/FilesList/FileListFilters.vue new file mode 100644 index 0000000000..4dab95821a --- /dev/null +++ b/src/views/FilesList/FileListFilters.vue @@ -0,0 +1,80 @@ + + + + + + diff --git a/src/views/FilesList/FilesList.vue b/src/views/FilesList/FilesList.vue new file mode 100644 index 0000000000..09b4c92737 --- /dev/null +++ b/src/views/FilesList/FilesList.vue @@ -0,0 +1,455 @@ + + + + + + diff --git a/src/views/FilesList/FilesListTableHeader.vue b/src/views/FilesList/FilesListTableHeader.vue new file mode 100644 index 0000000000..19211678b1 --- /dev/null +++ b/src/views/FilesList/FilesListTableHeader.vue @@ -0,0 +1,99 @@ + + + + + + diff --git a/src/views/FilesList/FilesListTableHeaderButton.vue b/src/views/FilesList/FilesListTableHeaderButton.vue new file mode 100644 index 0000000000..66f0e3c9da --- /dev/null +++ b/src/views/FilesList/FilesListTableHeaderButton.vue @@ -0,0 +1,88 @@ + + + + + + diff --git a/src/views/FilesList/FilesListVirtual.vue b/src/views/FilesList/FilesListVirtual.vue new file mode 100644 index 0000000000..6d13924bc1 --- /dev/null +++ b/src/views/FilesList/FilesListVirtual.vue @@ -0,0 +1,529 @@ + + + + + + + + diff --git a/src/views/FilesList/VirtualList.vue b/src/views/FilesList/VirtualList.vue new file mode 100644 index 0000000000..c9dd46320e --- /dev/null +++ b/src/views/FilesList/VirtualList.vue @@ -0,0 +1,92 @@ + + + + diff --git a/src/views/Timeline/Timeline.vue b/src/views/Timeline/Timeline.vue deleted file mode 100644 index d3ad50320b..0000000000 --- a/src/views/Timeline/Timeline.vue +++ /dev/null @@ -1,146 +0,0 @@ - - - - - diff --git a/tests/integration/features/file/list.feature b/tests/integration/features/file/list.feature index 5ce67f8f59..8f59a45a16 100644 --- a/tests/integration/features/file/list.feature +++ b/tests/integration/features/file/list.feature @@ -75,10 +75,10 @@ Feature: file-list | key | value | | (jq).ocs.data.data[0].name | document | | (jq).ocs.data.pagination.total | 5 | - | (jq).ocs.data.pagination.current | /file/list?page=1&length=2 | - | (jq).ocs.data.pagination.next | /file/list?page=2&length=2 | + | (jq).ocs.data.pagination.current | /ocsapp/apps/libresign/api/v1/file/list?length=2&page=1 | + | (jq).ocs.data.pagination.next | /ocsapp/apps/libresign/api/v1/file/list?length=2&page=2 | | (jq).ocs.data.pagination.prev | null | - | (jq).ocs.data.pagination.last | /file/list?page=3&length=2 | + | (jq).ocs.data.pagination.last | /ocsapp/apps/libresign/api/v1/file/list?length=2&page=3 | | (jq).ocs.data.pagination.first | null | # second page When sending "get" to ocs "/apps/libresign/api/v1/file/list?length=2&page=2" @@ -86,19 +86,19 @@ Feature: file-list | key | value | | (jq).ocs.data.data[0].name | document | | (jq).ocs.data.pagination.total | 5 | - | (jq).ocs.data.pagination.current | /file/list?page=2&length=2 | - | (jq).ocs.data.pagination.next | /file/list?page=3&length=2 | - | (jq).ocs.data.pagination.prev | /file/list?page=1&length=2 | - | (jq).ocs.data.pagination.last | /file/list?page=3&length=2 | - | (jq).ocs.data.pagination.first | /file/list?page=1&length=2 | + | (jq).ocs.data.pagination.current | /ocsapp/apps/libresign/api/v1/file/list?length=2&page=2 | + | (jq).ocs.data.pagination.next | /ocsapp/apps/libresign/api/v1/file/list?length=2&page=3 | + | (jq).ocs.data.pagination.prev | /ocsapp/apps/libresign/api/v1/file/list?length=2&page=1 | + | (jq).ocs.data.pagination.last | /ocsapp/apps/libresign/api/v1/file/list?length=2&page=3 | + | (jq).ocs.data.pagination.first | /ocsapp/apps/libresign/api/v1/file/list?length=2&page=1 | # last page - When sending "get" to ocs "/apps/libresign/api/v1/file/list?length=2&page=3" + When sending "get" to ocs "/apps/libresign/api/v1/file/list?page=3&length=2" Then the response should be a JSON array with the following mandatory values | key | value | | (jq).ocs.data.data[0].name | document | | (jq).ocs.data.pagination.total | 5 | - | (jq).ocs.data.pagination.current | /file/list?page=3&length=2 | + | (jq).ocs.data.pagination.current | /ocsapp/apps/libresign/api/v1/file/list?length=2&page=3 | | (jq).ocs.data.pagination.next | null | - | (jq).ocs.data.pagination.prev | /file/list?page=2&length=2 | + | (jq).ocs.data.pagination.prev | /ocsapp/apps/libresign/api/v1/file/list?length=2&page=2 | | (jq).ocs.data.pagination.last | null | - | (jq).ocs.data.pagination.first | /file/list?page=1&length=2 | + | (jq).ocs.data.pagination.first | /ocsapp/apps/libresign/api/v1/file/list?length=2&page=1 | diff --git a/tsconfig.json b/tsconfig.json index 4176c09e07..3d0d2e6764 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,4 +12,4 @@ "vueCompilerOptions": { "target": 2.7, } -} \ No newline at end of file +} diff --git a/webpack.config.js b/webpack.config.js index f223ef099d..208eed9198 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -3,6 +3,7 @@ const path = require('path') const BabelLoaderExcludeNodeModulesExcept = require('babel-loader-exclude-node-modules-except') const { EsbuildPlugin } = require('esbuild-loader') const nextcloudWebpackConfig = require('@nextcloud/webpack-vue-config') +const CopyPlugin = require('copy-webpack-plugin'); module.exports = merge(nextcloudWebpackConfig, { entry: { @@ -66,4 +67,14 @@ module.exports = merge(nextcloudWebpackConfig, { ], }, cache: true, + plugins: [ + new CopyPlugin({ + patterns: [ + { + from: 'node_modules/@libresign/vue-pdf-editor/dist/pdf.worker.min.mjs', + to: '', + }, + ], + }), + ], })