From 7202680a39ecdce2937489417e1841cde1d961ef Mon Sep 17 00:00:00 2001 From: Dion Date: Wed, 21 Feb 2024 21:10:57 +0100 Subject: [PATCH] add imageformat to directory && add UI to open files --- .../desktop-editor/amount-confirmation.json | 1 + .../mock/api/desktop-editor/open.json | 9 + starsky-tools/mock/api/env/features.json | 2 +- starsky-tools/mock/set-router.js | 84 +++-- .../Service/OpenEditorPreflight.cs | 5 + .../starsky.feature.import/Services/Import.cs | 1 + .../Helpers/StatusCodesHelper.cs | 18 +- .../Query/QuerySingleItem.cs | 1 + .../Helpers/ExtensionRolesHelper.cs | 5 +- .../SyncServices/SyncFolder.cs | 1 + .../WatcherHelpers/SyncWatcherConnector.cs | 2 + .../Controllers/DesktopEditorController.cs | 4 +- starsky/starsky/Controllers/DiskController.cs | 5 +- ...menu-option-desktop-editor-open.spec.tsx__ | 190 +++++++++++ ...enu-option-desktop-editor-open.stories.tsx | 52 +++ .../menu-option-desktop-editor-open.tsx | 205 ++++++++++++ .../organisms/menu-archive/menu-archive.tsx | 8 + ...sktop-editor-open-confirmation.stories.tsx | 29 ++ ...modal-desktop-editor-open-confirmation.tsx | 132 ++++++++ .../clientapp/src/interfaces/IEnvFeatures.ts | 1 + .../src/localization/localization.json | 20 ++ .../starsky/clientapp/src/shared/url-query.ts | 8 + .../Services/DeleteItemTest.cs | 307 ++++++++++-------- 23 files changed, 917 insertions(+), 173 deletions(-) create mode 100644 starsky-tools/mock/api/desktop-editor/amount-confirmation.json create mode 100644 starsky-tools/mock/api/desktop-editor/open.json create mode 100644 starsky/starsky/clientapp/src/components/molecules/menu-option-desktop-editor-open/_menu-option-desktop-editor-open.spec.tsx__ create mode 100644 starsky/starsky/clientapp/src/components/molecules/menu-option-desktop-editor-open/menu-option-desktop-editor-open.stories.tsx create mode 100644 starsky/starsky/clientapp/src/components/molecules/menu-option-desktop-editor-open/menu-option-desktop-editor-open.tsx create mode 100644 starsky/starsky/clientapp/src/components/organisms/modal-desktop-editor-open-confirmation/modal-desktop-editor-open-confirmation.stories.tsx create mode 100644 starsky/starsky/clientapp/src/components/organisms/modal-desktop-editor-open-confirmation/modal-desktop-editor-open-confirmation.tsx diff --git a/starsky-tools/mock/api/desktop-editor/amount-confirmation.json b/starsky-tools/mock/api/desktop-editor/amount-confirmation.json new file mode 100644 index 0000000000..f32a5804e2 --- /dev/null +++ b/starsky-tools/mock/api/desktop-editor/amount-confirmation.json @@ -0,0 +1 @@ +true \ No newline at end of file diff --git a/starsky-tools/mock/api/desktop-editor/open.json b/starsky-tools/mock/api/desktop-editor/open.json new file mode 100644 index 0000000000..61ad49a945 --- /dev/null +++ b/starsky-tools/mock/api/desktop-editor/open.json @@ -0,0 +1,9 @@ +[ + { + "subPath": "/20221029_101722_DSC05623.arw", + "fullFilePath": "/data/testcontent//20221029_101722_DSC05623.arw", + "imageFormat": 12, + "status": 8, + "appPath": "" + } +] diff --git a/starsky-tools/mock/api/env/features.json b/starsky-tools/mock/api/env/features.json index 4f38575c57..ec7f18de73 100644 --- a/starsky-tools/mock/api/env/features.json +++ b/starsky-tools/mock/api/env/features.json @@ -1 +1 @@ -{"systemTrashEnabled":false,"useLocalDesktop":false, "openEditorEnabled": false} \ No newline at end of file +{"systemTrashEnabled":false,"useLocalDesktop":false, "openEditorEnabled": true} \ No newline at end of file diff --git a/starsky-tools/mock/set-router.js b/starsky-tools/mock/set-router.js index 1f587ebe1a..3b7450c507 100644 --- a/starsky-tools/mock/set-router.js +++ b/starsky-tools/mock/set-router.js @@ -1,43 +1,45 @@ const express = require("express"); const path = require("path"); -var apiAccountChangeSecretIndex = require("./api/account/change-secret/index.json"); -var apiAccountPermissionsIndex = require("./api/account/permissions/index.json"); +const apiAccountChangeSecretIndex = require("./api/account/change-secret/index.json"); +const apiAccountPermissionsIndex = require("./api/account/permissions/index.json"); -var accountStatus = require("./api/account/status/index.json"); -var apiHealthDetails = require("./api/health/details/index.json"); -var apiHealthCheckForUpdates = require("./api/health/check-for-updates/index.json"); -var apiGeoReverseLookup = require("./api/geo-reverse-lookup/index.json"); +const accountStatus = require("./api/account/status/index.json"); +const apiHealthDetails = require("./api/health/details/index.json"); +const apiHealthCheckForUpdates = require("./api/health/check-for-updates/index.json"); +const apiGeoReverseLookup = require("./api/geo-reverse-lookup/index.json"); -var apiIndexIndex = require("./api/index/index.json"); -var apiIndex__Starsky = require("./api/index/__starsky.json"); -var apiIndex0001 = require("./api/index/0001.json"); -var apiIndex0001_toggleDeleted = require("./api/index/0001_toggleDeleted.json"); +const apiIndexIndex = require("./api/index/index.json"); +const apiIndex__Starsky = require("./api/index/__starsky.json"); +const apiIndex0001 = require("./api/index/0001.json"); +const apiIndex0001_toggleDeleted = require("./api/index/0001_toggleDeleted.json"); -var apiIndex__Starsky01dif = require("./api/index/__starsky_01-dif.json"); -var apiIndex__Starsky01difColorclass0 = require("./api/index/__starsky_01-dif_colorclass0.json"); +const apiIndex__Starsky01dif = require("./api/index/__starsky_01-dif.json"); +const apiIndex__Starsky01difColorclass0 = require("./api/index/__starsky_01-dif_colorclass0.json"); -var apiIndex__Starsky01dif20180101170001 = require("./api/index/__starsky_01-dif-2018.01.01.17.00.01.json"); +const apiIndex__Starsky01dif20180101170001 = require("./api/index/__starsky_01-dif-2018.01.01.17.00.01.json"); -var apiInfo__testJpg = require("./api/info/test.jpg.json"); +const apiInfo__testJpg = require("./api/info/test.jpg.json"); -var apiSearchTrash = require("./api/search/trash/index.json"); -var apiSearch = require("./api/search/index.json"); -var apiSearchTest = require("./api/search/test.json"); -var apiSearchTest1 = require("./api/search/test1.json"); -var apiUpdate__Starsky01dif20180101170001_Deleted = require("./api/update/__starsky_01-dif-2018.01.01.17.00.01_Deleted.json"); -var apiUpdate__Starsky01dif20180101170001_Ok = require("./api/update/__starsky_01-dif-2018.01.01.17.00.01_Ok.json"); +const apiSearchTrash = require("./api/search/trash/index.json"); +const apiSearch = require("./api/search/index.json"); +const apiSearchTest = require("./api/search/test.json"); +const apiSearchTest1 = require("./api/search/test1.json"); +const apiUpdate__Starsky01dif20180101170001_Deleted = require("./api/update/__starsky_01-dif-2018.01.01.17.00.01_Deleted.json"); +const apiUpdate__Starsky01dif20180101170001_Ok = require("./api/update/__starsky_01-dif-2018.01.01.17.00.01_Ok.json"); -var apiEnvIndex = require("./api/env/index.json"); -var apiEnvFeatures = require("./api/env/features.json"); +const apiEnvIndex = require("./api/env/index.json"); +const apiEnvFeatures = require("./api/env/features.json"); -var apiPublishIndex = require("./api/publish/index.json"); -var apiPublishCreateIndex = require("./api/publish/create/index.json"); +const apiPublishIndex = require("./api/publish/index.json"); +const apiPublishCreateIndex = require("./api/publish/create/index.json"); -var githubComReposQdrawStarskyReleaseIndex = require("./github.com/repos/qdraw/starsky/releases/index.json"); +const apiDeskopEditorOpen = require("./api/desktop-editor/open.json"); + +const githubComReposQdrawStarskyReleaseIndex = require("./github.com/repos/qdraw/starsky/releases/index.json"); function setRouter(app, isStoryBook = false) { - var prefix = "/starsky"; + const prefix = "/starsky"; app.use( prefix + "/api/thumbnail", @@ -59,7 +61,7 @@ function setRouter(app, isStoryBook = false) { res.json(accountStatus); }); - var isChangePasswordSuccess = false; + let isChangePasswordSuccess = false; app.post(prefix + "/api/account/change-secret/", (req, res) => { console.log(req.body); @@ -159,7 +161,7 @@ function setRouter(app, isStoryBook = false) { return res.json("not found"); }); - var isDeleted = true; + let isDeleted = true; app.post(prefix + "/api/update", (req, res) => { if (!req.body) { res.statusCode = 500; @@ -248,6 +250,30 @@ function setRouter(app, isStoryBook = false) { return res.json(apiEnvIndex); }); + app.post(prefix + "/api/desktop-editor/amount-confirmation", (req, res) => { + if (!req.body) { + return res.json("no body ~ the normal api does ignore it"); + } + console.log(`amount-confirmation ${req.body.f}`); + + return res.json(req.body.f !== "/true.jpg"); + }); + + app.post(prefix + "/api/desktop-editor/open", (req, res) => { + if (!req.body) { + return res.json("no body ~ the normal api does ignore it"); + } + console.log(`open ${req.body.f}`); + + if (req.body.f === "/true.jpg") { + res.statusCode = 400; + res.json() + return + } + + return res.json(apiDeskopEditorOpen); + }); + app.get(prefix + "/api/health/application-insights", (req, res) => { res.set("Content-Type", "application/javascript"); return res.send(""); @@ -282,7 +308,7 @@ function setRouter(app, isStoryBook = false) { }); // Simulate waiting - var fakeLoading = {}; + let fakeLoading = {}; app.get(prefix + "/export/zip/:id", (req, res) => { if (!fakeLoading[req.params.id]) { fakeLoading[req.params.id] = 0; diff --git a/starsky/starsky.feature.desktop/Service/OpenEditorPreflight.cs b/starsky/starsky.feature.desktop/Service/OpenEditorPreflight.cs index 3b6c606fa3..94687db487 100644 --- a/starsky/starsky.feature.desktop/Service/OpenEditorPreflight.cs +++ b/starsky/starsky.feature.desktop/Service/OpenEditorPreflight.cs @@ -63,6 +63,11 @@ private string GetDesktopEditorPath(ExtensionRolesHelper.ImageFormat imageFormat var appPath = appSettingsDefaultEditor?.ApplicationPath ?? string.Empty; + if ( string.IsNullOrEmpty(appPath) ) + { + return string.Empty; + } + // Under Mac OS the ApplicationPath is a .app folder // Under Windows the ApplicationPath is a .exe file if ( _hostFileSystem.IsFolderOrFile(appPath) != diff --git a/starsky/starsky.feature.import/Services/Import.cs b/starsky/starsky.feature.import/Services/Import.cs index a0104c7b81..8a00bdaf2a 100644 --- a/starsky/starsky.feature.import/Services/Import.cs +++ b/starsky/starsky.feature.import/Services/Import.cs @@ -907,6 +907,7 @@ private async Task CreateNewDatabaseDirectory(string parentPath) { AddToDatabase = DateTime.UtcNow, IsDirectory = true, + ImageFormat = ExtensionRolesHelper.ImageFormat.directory, ColorClass = ColorClassParser.Color.None }; diff --git a/starsky/starsky.foundation.database/Helpers/StatusCodesHelper.cs b/starsky/starsky.foundation.database/Helpers/StatusCodesHelper.cs index b43520434b..abc6aff159 100644 --- a/starsky/starsky.foundation.database/Helpers/StatusCodesHelper.cs +++ b/starsky/starsky.foundation.database/Helpers/StatusCodesHelper.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using starsky.foundation.database.Models; +using starsky.foundation.platform.Helpers; using starsky.foundation.platform.Models; namespace starsky.foundation.database.Helpers @@ -16,7 +17,8 @@ public StatusCodesHelper(AppSettings appSettings) public FileIndexItem.ExifStatus IsReadOnlyStatus(FileIndexItem fileIndexItem) { - if ( fileIndexItem.IsDirectory == true && _appSettings.IsReadOnly(fileIndexItem.FilePath!) ) + if ( fileIndexItem.IsDirectory == true && + _appSettings.IsReadOnly(fileIndexItem.FilePath!) ) { return FileIndexItem.ExifStatus.DirReadOnly; } @@ -53,13 +55,16 @@ public FileIndexItem.ExifStatus IsReadOnlyStatus(DetailView? detailView) public static FileIndexItem.ExifStatus IsDeletedStatus(FileIndexItem? fileIndexItem) { - return fileIndexItem?.Tags != null && fileIndexItem.Tags.Contains(TrashKeyword.TrashKeywordString) ? - FileIndexItem.ExifStatus.Deleted : FileIndexItem.ExifStatus.Default; + return fileIndexItem?.Tags != null && + fileIndexItem.Tags.Contains(TrashKeyword.TrashKeywordString) + ? FileIndexItem.ExifStatus.Deleted + : FileIndexItem.ExifStatus.Default; } public static FileIndexItem.ExifStatus IsDeletedStatus(DetailView? detailView) { - if ( !string.IsNullOrEmpty(detailView?.FileIndexItem?.Tags) && detailView.FileIndexItem.Tags.Contains(TrashKeyword.TrashKeywordString) ) + if ( !string.IsNullOrEmpty(detailView?.FileIndexItem?.Tags) && + detailView.FileIndexItem.Tags.Contains(TrashKeyword.TrashKeywordString) ) { return FileIndexItem.ExifStatus.Deleted; } @@ -83,6 +88,7 @@ public static bool ReturnExifStatusError(FileIndexItem statusModel, { case FileIndexItem.ExifStatus.DirReadOnly: statusModel.IsDirectory = true; + statusModel.ImageFormat = ExtensionRolesHelper.ImageFormat.directory; statusModel.Status = FileIndexItem.ExifStatus.DirReadOnly; fileIndexResultsList.Add(statusModel); return true; @@ -107,6 +113,7 @@ public static bool ReturnExifStatusError(FileIndexItem statusModel, fileIndexResultsList.Add(statusModel); return true; } + return false; } @@ -120,6 +127,7 @@ public static bool ReadonlyDenied(FileIndexItem statusModel, fileIndexResultsList.Add(statusModel); return true; } + return false; } @@ -132,7 +140,5 @@ public static void ReadonlyAllowed(FileIndexItem statusModel, statusModel.Status = FileIndexItem.ExifStatus.ReadOnly; fileIndexResultsList.Add(statusModel); } - - } } diff --git a/starsky/starsky.foundation.database/Query/QuerySingleItem.cs b/starsky/starsky.foundation.database/Query/QuerySingleItem.cs index 964475a218..f4d83ca5d5 100644 --- a/starsky/starsky.foundation.database/Query/QuerySingleItem.cs +++ b/starsky/starsky.foundation.database/Query/QuerySingleItem.cs @@ -119,6 +119,7 @@ public partial class Query if ( currentFileIndexItem.IsDirectory == true ) { currentFileIndexItem.CollectionPaths = new List { singleItemDbPath }; + return new DetailView { IsDirectory = true, diff --git a/starsky/starsky.foundation.platform/Helpers/ExtensionRolesHelper.cs b/starsky/starsky.foundation.platform/Helpers/ExtensionRolesHelper.cs index 8c23c89da1..e65a253f58 100644 --- a/starsky/starsky.foundation.platform/Helpers/ExtensionRolesHelper.cs +++ b/starsky/starsky.foundation.platform/Helpers/ExtensionRolesHelper.cs @@ -372,7 +372,10 @@ public enum ImageFormat mp4 = 50, // archives - zip = 60 + zip = 60, + + // folder + directory = 1000 } diff --git a/starsky/starsky.foundation.sync/SyncServices/SyncFolder.cs b/starsky/starsky.foundation.sync/SyncServices/SyncFolder.cs index 98339af010..f44ea093c3 100644 --- a/starsky/starsky.foundation.sync/SyncServices/SyncFolder.cs +++ b/starsky/starsky.foundation.sync/SyncServices/SyncFolder.cs @@ -145,6 +145,7 @@ internal async Task CompareFolderListAndFixMissingFolders(List subPaths, await _query.AddItemAsync(new FileIndexItem(path) { IsDirectory = true, + ImageFormat = ExtensionRolesHelper.ImageFormat.directory, AddToDatabase = DateTime.UtcNow, ColorClass = ColorClassParser.Color.None }); diff --git a/starsky/starsky.foundation.sync/WatcherHelpers/SyncWatcherConnector.cs b/starsky/starsky.foundation.sync/WatcherHelpers/SyncWatcherConnector.cs index 39d619fcff..97039e6441 100644 --- a/starsky/starsky.foundation.sync/WatcherHelpers/SyncWatcherConnector.cs +++ b/starsky/starsky.foundation.sync/WatcherHelpers/SyncWatcherConnector.cs @@ -13,6 +13,7 @@ using starsky.foundation.database.Models; using starsky.foundation.database.Query; using starsky.foundation.platform.Enums; +using starsky.foundation.platform.Helpers; using starsky.foundation.platform.Interfaces; using starsky.foundation.platform.JsonConverter; using starsky.foundation.platform.Models; @@ -114,6 +115,7 @@ private async Task> SyncTaskInternal( syncData.Add(new FileIndexItem(_appSettings.FullPathToDatabaseStyle(fullFilePath)) { IsDirectory = true, + ImageFormat = ExtensionRolesHelper.ImageFormat.directory, Status = FileIndexItem.ExifStatus.NotFoundSourceMissing }); diff --git a/starsky/starsky/Controllers/DesktopEditorController.cs b/starsky/starsky/Controllers/DesktopEditorController.cs index 6b57335577..7b20b63107 100644 --- a/starsky/starsky/Controllers/DesktopEditorController.cs +++ b/starsky/starsky/Controllers/DesktopEditorController.cs @@ -26,7 +26,7 @@ public DesktopEditorController(IOpenEditorDesktopService openEditorDesktopServic /// returns a list of items from the database /// subPath not found in the database /// User unauthorized - [HttpGet("/api/desktop-editor/open")] + [HttpPost("/api/desktop-editor/open")] [Produces("application/json")] [ProducesResponseType(typeof(List), 200)] [ProducesResponseType(typeof(List), 204)] @@ -59,7 +59,7 @@ public async Task OpenAsync( /// /// bool, true is no confirmation, false is ask confirmation /// User unauthorized - [HttpGet("/api/desktop-editor/amount-confirmation")] + [HttpPost("/api/desktop-editor/amount-confirmation")] [Produces("application/json")] [ProducesResponseType(typeof(bool), 200)] [ProducesResponseType(401)] diff --git a/starsky/starsky/Controllers/DiskController.cs b/starsky/starsky/Controllers/DiskController.cs index d7b12c3887..e8c8666dc4 100644 --- a/starsky/starsky/Controllers/DiskController.cs +++ b/starsky/starsky/Controllers/DiskController.cs @@ -74,7 +74,10 @@ public async Task Mkdir(string f) continue; } - await _query.AddItemAsync(new FileIndexItem(subPath) { IsDirectory = true }); + await _query.AddItemAsync(new FileIndexItem(subPath) + { + IsDirectory = true, ImageFormat = ExtensionRolesHelper.ImageFormat.directory + }); // add to fs _iStorage.CreateDirectory(subPath); diff --git a/starsky/starsky/clientapp/src/components/molecules/menu-option-desktop-editor-open/_menu-option-desktop-editor-open.spec.tsx__ b/starsky/starsky/clientapp/src/components/molecules/menu-option-desktop-editor-open/_menu-option-desktop-editor-open.spec.tsx__ new file mode 100644 index 0000000000..be0f6790f8 --- /dev/null +++ b/starsky/starsky/clientapp/src/components/molecules/menu-option-desktop-editor-open/_menu-option-desktop-editor-open.spec.tsx__ @@ -0,0 +1,190 @@ +import { fireEvent, render, screen } from "@testing-library/react"; +import { act } from "react-dom/test-utils"; +import localization from "../../../localization/localization.json"; +import * as Modal from "../../atoms/modal/modal"; +import * as ModalMoveFolderToTrash from "../../organisms/modal-move-folder-to-trash/modal-move-folder-to-trash"; +import MenuOptionMoveFolderToTrash from "./menu-option-move-folder-to-trash"; + +describe("MenuOptionMoveFolderToTrash", () => { + it("renders the menu option correctly", () => { + render( + + ); + + expect(screen.getByText(localization.MessageMoveCurrentFolderToTrash.en)).toBeTruthy(); + }); + + it("opens the modal when the menu option is clicked", () => { + jest + .spyOn(ModalMoveFolderToTrash, "default") + .mockImplementationOnce(() =>
); + + render( + + ); + + const menuOption = screen.getByTestId("move-folder-to-trash"); + fireEvent.click(menuOption); + + expect(screen.getByTestId("modal-move-folder-to-trash")).toBeTruthy(); + }); + + it("opens the modal when the menu option is keyDowned", () => { + jest + .spyOn(ModalMoveFolderToTrash, "default") + .mockImplementationOnce(() =>
); + + render( + + ); + + const menuOption = screen.getByTestId("move-folder-to-trash"); + fireEvent.keyDown(menuOption, { key: "Enter" }); + + expect(screen.getByTestId("modal-move-folder-to-trash")).toBeTruthy(); + }); + + it("not opens the modal when the menu option is keyDowned but wrong key so ignored", () => { + jest + .spyOn(ModalMoveFolderToTrash, "default") + .mockImplementationOnce(() =>
); + + render( + + ); + + const menuOption = screen.getByTestId("move-folder-to-trash"); + fireEvent.keyDown(menuOption, { key: "Tab" }); + + expect(screen.queryByTestId("modal-move-folder-to-trash")).toBeFalsy(); + }); + + it("opens the modal when the menu option is clicked 1", () => { + console.log("----------"); + + const modalSpy = jest.spyOn(Modal, "default").mockImplementationOnce((props) => { + act(() => { + props.handleExit(); + }); + return <>{props.children}; + }); + + jest.spyOn(ModalMoveFolderToTrash, "default").mockImplementationOnce((props) => { + act(() => { + props.handleExit(); + }); + return <>; + }); + + const setEnableMoreMenuSpy = jest.fn(); + render( + + ); + + const menuOption = screen.getByTestId("move-folder-to-trash"); + fireEvent.click(menuOption); + + expect(screen.getByTestId("move-folder-to-trash")).toBeTruthy(); + + expect(setEnableMoreMenuSpy).toHaveBeenCalledTimes(1); + expect(setEnableMoreMenuSpy).toHaveBeenCalledWith(false); + + expect(modalSpy).toHaveBeenCalledTimes(0); + }); + + it("opens the modal when the menu option is keyDown tab so skip", () => { + console.log("----------"); + + const modalSpy = jest.spyOn(Modal, "default").mockImplementationOnce((props) => { + act(() => { + props.handleExit(); + }); + return <>{props.children}; + }); + + jest.spyOn(ModalMoveFolderToTrash, "default").mockImplementationOnce((props) => { + act(() => { + props.handleExit(); + }); + return <>; + }); + + const setEnableMoreMenuSpy = jest.fn(); + render( + + ); + + const menuOption = screen.getByTestId("move-folder-to-trash"); + fireEvent.keyDown(menuOption, { key: "Tab" }); + + expect(screen.getByTestId("move-folder-to-trash")).toBeTruthy(); + + expect(setEnableMoreMenuSpy).toHaveBeenCalledTimes(0); + + expect(modalSpy).toHaveBeenCalledTimes(0); + }); + + it("opens the modal when the menu option is keyDown enter 1", () => { + console.log("----------"); + + const modalSpy = jest.spyOn(Modal, "default").mockImplementationOnce((props) => { + act(() => { + props.handleExit(); + }); + return <>{props.children}; + }); + + jest.spyOn(ModalMoveFolderToTrash, "default").mockImplementationOnce((props) => { + act(() => { + props.handleExit(); + }); + return <>; + }); + + const setEnableMoreMenuSpy = jest.fn(); + render( + + ); + + const menuOption = screen.getByTestId("move-folder-to-trash"); + fireEvent.keyDown(menuOption, { key: "Enter" }); + + expect(screen.getByTestId("move-folder-to-trash")).toBeTruthy(); + + expect(setEnableMoreMenuSpy).toHaveBeenCalledTimes(1); + expect(setEnableMoreMenuSpy).toHaveBeenCalledWith(false); + + expect(modalSpy).toHaveBeenCalledTimes(0); + }); +}); diff --git a/starsky/starsky/clientapp/src/components/molecules/menu-option-desktop-editor-open/menu-option-desktop-editor-open.stories.tsx b/starsky/starsky/clientapp/src/components/molecules/menu-option-desktop-editor-open/menu-option-desktop-editor-open.stories.tsx new file mode 100644 index 0000000000..9b93a9f3de --- /dev/null +++ b/starsky/starsky/clientapp/src/components/molecules/menu-option-desktop-editor-open/menu-option-desktop-editor-open.stories.tsx @@ -0,0 +1,52 @@ +import MoreMenu from "../../atoms/more-menu/more-menu"; +import MenuOptionDesktopEditorOpen from "./menu-option-desktop-editor-open"; + +export default { + title: "components/molecules/menu-option-desktop-editor-open" +}; + +export const Default = () => { + return ( + {}}> + + + ); +}; + +Default.storyName = "default (no dialog)"; + +export const Case2 = () => { + return ( + {}}> + + + ); +}; + +Case2.storyName = "with dialog"; diff --git a/starsky/starsky/clientapp/src/components/molecules/menu-option-desktop-editor-open/menu-option-desktop-editor-open.tsx b/starsky/starsky/clientapp/src/components/molecules/menu-option-desktop-editor-open/menu-option-desktop-editor-open.tsx new file mode 100644 index 0000000000..f769f0260e --- /dev/null +++ b/starsky/starsky/clientapp/src/components/molecules/menu-option-desktop-editor-open/menu-option-desktop-editor-open.tsx @@ -0,0 +1,205 @@ +import React, { memo, useState } from "react"; +import useFetch from "../../../hooks/use-fetch"; +import useGlobalSettings from "../../../hooks/use-global-settings"; +import useHotKeys from "../../../hooks/use-keyboard/use-hotkeys"; +import useLocation from "../../../hooks/use-location/use-location"; +import { IArchiveProps } from "../../../interfaces/IArchiveProps"; +import { PageType } from "../../../interfaces/IDetailView"; +import { IEnvFeatures } from "../../../interfaces/IEnvFeatures"; +import localization from "../../../localization/localization.json"; +import FetchPost from "../../../shared/fetch/fetch-post"; +import { Language } from "../../../shared/language"; +import { URLPath } from "../../../shared/url-path"; +import { UrlQuery } from "../../../shared/url-query"; +import MenuOption from "../../atoms/menu-option/menu-option"; +import Notification, { NotificationType } from "../../atoms/notification/notification"; +import ModalDesktopEditorOpenConfirmation from "../../organisms/modal-desktop-editor-open-confirmation/modal-desktop-editor-open-confirmation"; + +interface IMenuOptionDesktopEditorOpenProps { + state: IArchiveProps; + select: string[]; + isReadOnly: boolean; + setEnableMoreMenu?: React.Dispatch>; +} + +async function openDesktop( + select: string[], + collections: boolean, + state: IArchiveProps, + setIsError: React.Dispatch>, + messageDesktopEditorUnableToOpen: string +) { + const toDesktopOpenList = new URLPath().MergeSelectFileIndexItem(select, state.fileIndexItems); + if (!toDesktopOpenList) return; + const selectParams = new URLPath().ArrayToCommaSeparatedStringOneParent(toDesktopOpenList, ""); + const urlOpen = new UrlQuery().UrlApiDesktopEditorOpen(); + + const bodyParams = new URLSearchParams(); + bodyParams.append("f", selectParams); + bodyParams.append("collections", collections.toString()); + + const openDesktopResult = await FetchPost(urlOpen, bodyParams.toString()); + if (openDesktopResult.statusCode >= 300) { + setIsError(messageDesktopEditorUnableToOpen); + } +} + +async function startMenuOptionDesktopEditorOpen( + select: string[], + collections: boolean, + state: IArchiveProps, + setIsError: React.Dispatch>, + messageDesktopEditorUnableToOpen: string, + setModalConfirmationOpenFiles: (value: React.SetStateAction) => void +) { + const toDesktopOpenList = new URLPath().MergeSelectFileIndexItem(select, state.fileIndexItems); + if (!toDesktopOpenList) return; + const selectParams = new URLPath().ArrayToCommaSeparatedStringOneParent(toDesktopOpenList, ""); + const urlCheck = new UrlQuery().UrlApiDesktopEditorOpenAmountConfirmationChecker(); + + const bodyParams = new URLSearchParams(); + bodyParams.append("f", selectParams); + + const openWithoutConformationResult = (await FetchPost(urlCheck, bodyParams.toString())).data; + if (openWithoutConformationResult === false) { + setModalConfirmationOpenFiles(true); + return; + } + await openDesktop(select, collections, state, setIsError, messageDesktopEditorUnableToOpen); +} + +const MenuOptionDesktopEditorOpen: React.FunctionComponent = + memo(({ state, select, isReadOnly }) => { + const featuresResult = useFetch(new UrlQuery().UrlApiFeaturesAppSettings(), "get"); + const dataFeatures = featuresResult?.data as IEnvFeatures | undefined; + const history = useLocation(); + + // Get language keys + const settings = useGlobalSettings(); + const language = new Language(settings.language); + const MessageDesktopEditorUnableToOpen = language.key( + localization.MessageDesktopEditorUnableToOpen + ); + + // for showing a notification + const [isError, setIsError] = useState(""); + + const [modalConfirmationOpenFiles, setModalConfirmationOpenFiles] = useState(false); + + const isCollections = + state.pageType !== PageType.Search + ? new URLPath().StringToIUrl(history.location.search).collections !== false + : false; + + /** + * Open editor with keys + */ + useHotKeys({ key: "e", ctrlKeyOrMetaKey: true }, () => { + console.log("hi"); + + startMenuOptionDesktopEditorOpen( + select, + isCollections, + state, + setIsError, + MessageDesktopEditorUnableToOpen, + setModalConfirmationOpenFiles + ).then(() => { + // do nothing + }); + }); + + return ( + <> + {/* Modal move folder to trash */} + {modalConfirmationOpenFiles ? ( + { + setModalConfirmationOpenFiles(!modalConfirmationOpenFiles); + }} + select={select} + state={state} + isCollections={isCollections} + setIsLoading={() => {}} + isOpen={modalConfirmationOpenFiles} + /> + ) : null} + + {isError !== "" ? ( + setIsError("")} type={NotificationType.danger}> + {isError} + + ) : null} + + {select.length >= 1 && dataFeatures?.openEditorEnabled === true ? ( + + startMenuOptionDesktopEditorOpen( + select, + isCollections, + state, + setIsError, + MessageDesktopEditorUnableToOpen, + setModalConfirmationOpenFiles + ) + } + localization={ + select.length === 1 + ? localization.MessageDesktopEditorOpenSingleFile + : localization.MessageDesktopEditorOpenMultipleFiles + } + /> + ) : null} + + ); + }); + +export default MenuOptionDesktopEditorOpen; + +// async function moveToTrashSelection() { +// if (!select || isReadOnly) return; + +// const toUndoTrashList = new URLPath().MergeSelectFileIndexItem(select, state.fileIndexItems); + +// if (!toUndoTrashList) return; +// const selectParams = new URLPath().ArrayToCommaSeparatedStringOneParent(toUndoTrashList, ""); +// if (selectParams.length === 0) return; + +// const bodyParams = new URLSearchParams(); +// // noinspection PointlessBooleanExpressionJS +// const collections = new URLPath().StringToIUrl(history.location.search).collections !== false; + +// bodyParams.append("f", selectParams); +// bodyParams.set("Tags", "!delete!"); +// bodyParams.set("append", "true"); +// bodyParams.set("Colorclass", "8"); +// bodyParams.set("collections", collections.toString()); + +// const resultDo = await FetchPost(new UrlQuery().UrlMoveToTrashApi(), bodyParams.toString()); + +// if ( +// resultDo.statusCode === 404 || +// resultDo.statusCode === 400 || +// resultDo.statusCode === 500 || +// resultDo.statusCode === 502 +// ) { +// return; +// } + +// undoSelection(); +// dispatch({ type: "remove", toRemoveFileList: toUndoTrashList }); +// ClearSearchCache(history.location.search); +// // Client side Caching: the order of files in a normal folder has changed +// new FileListCache().CacheCleanEverything(); +// } + +// /** +// * When pressing delete its moved to the trash +// */ +// useHotKeys({ key: "E", ctrlKeyOrMetaKey: true }, () => { +// moveToTrashSelection().then(() => { +// // do nothing +// }); +// }); diff --git a/starsky/starsky/clientapp/src/components/organisms/menu-archive/menu-archive.tsx b/starsky/starsky/clientapp/src/components/organisms/menu-archive/menu-archive.tsx index 91dc76f904..b3db00ceea 100644 --- a/starsky/starsky/clientapp/src/components/organisms/menu-archive/menu-archive.tsx +++ b/starsky/starsky/clientapp/src/components/organisms/menu-archive/menu-archive.tsx @@ -14,6 +14,7 @@ import HamburgerMenuToggle from "../../atoms/hamburger-menu-toggle/hamburger-men import MenuOptionModal from "../../atoms/menu-option-modal/menu-option-modal"; import MoreMenu from "../../atoms/more-menu/more-menu"; import MenuSearchBar from "../../molecules/menu-inline-search/menu-inline-search"; +import MenuOptionDesktopEditorOpen from "../../molecules/menu-option-desktop-editor-open/menu-option-desktop-editor-open"; import MenuOptionMoveFolderToTrash from "../../molecules/menu-option-move-folder-to-trash/menu-option-move-folder-to-trash"; import MenuOptionMoveToTrash from "../../molecules/menu-option-move-to-trash/menu-option-move-to-trash"; import { MenuOptionSelectionAll } from "../../molecules/menu-option-selection-all/menu-option-selection-all"; @@ -285,6 +286,13 @@ const MenuArchive: React.FunctionComponent = memo(() => { setSelect={setSelect} isReadOnly={readOnly} /> + + ) : null} { + return ( + {}} + isOpen={true} + handleExit={() => {}} + /> + ); +}; + +Default.storyName = "default"; diff --git a/starsky/starsky/clientapp/src/components/organisms/modal-desktop-editor-open-confirmation/modal-desktop-editor-open-confirmation.tsx b/starsky/starsky/clientapp/src/components/organisms/modal-desktop-editor-open-confirmation/modal-desktop-editor-open-confirmation.tsx new file mode 100644 index 0000000000..52da8e87e5 --- /dev/null +++ b/starsky/starsky/clientapp/src/components/organisms/modal-desktop-editor-open-confirmation/modal-desktop-editor-open-confirmation.tsx @@ -0,0 +1,132 @@ +import { useState } from "react"; +import useGlobalSettings from "../../../hooks/use-global-settings"; +import { IArchiveProps } from "../../../interfaces/IArchiveProps"; +import localization from "../../../localization/localization.json"; +import FetchPost from "../../../shared/fetch/fetch-post"; +import { Language } from "../../../shared/language"; +import { URLPath } from "../../../shared/url-path"; +import { UrlQuery } from "../../../shared/url-query"; +import Modal from "../../atoms/modal/modal"; + +interface IModalDesktopEditorOpenConfirmationProps { + isOpen: boolean; + select: Array | undefined; + handleExit(): void; + state: IArchiveProps; + setIsLoading: React.Dispatch>; + isCollections: boolean; +} + +async function OpenDesktop( + select: string[], + collections: boolean, + state: IArchiveProps, + setIsError: React.Dispatch>, + messageDesktopEditorUnableToOpen: string +): Promise { + const toDesktopOpenList = new URLPath().MergeSelectFileIndexItem(select, state.fileIndexItems); + if (!toDesktopOpenList) return false; + const selectParams = new URLPath().ArrayToCommaSeparatedStringOneParent(toDesktopOpenList, ""); + const urlOpen = new UrlQuery().UrlApiDesktopEditorOpen(); + + const bodyParams = new URLSearchParams(); + bodyParams.append("f", selectParams); + bodyParams.append("collections", collections.toString()); + + const openDesktopResult = await FetchPost(urlOpen, bodyParams.toString()); + if (openDesktopResult.statusCode >= 300) { + setIsError(messageDesktopEditorUnableToOpen); + } + return true; +} + +const ModalDesktopEditorOpenConfirmation: React.FunctionComponent< + IModalDesktopEditorOpenConfirmationProps +> = ({ select, handleExit, isOpen, state, isCollections }) => { + // content + const settings = useGlobalSettings(); + const language = new Language(settings.language); + const MessageDesktopEditorConfirmationIntroText = language.key( + localization.MessageDesktopEditorConfirmationIntroText + ); + const MessageDesktopEditorConfirmationHeading = language.key( + localization.MessageDesktopEditorConfirmationHeading + ); + const MessageCancel = language.key(localization.MessageCancel); + const MessageDesktopEditorOpenMultipleFiles = language.key( + localization.MessageDesktopEditorOpenMultipleFiles + ); + const MessageDesktopEditorUnableToOpen = language.key( + localization.MessageDesktopEditorUnableToOpen + ); + + // for showing a notification + const [isError, setIsError] = useState(""); + + return ( + { + handleExit(); + }} + > + <> +
{MessageDesktopEditorConfirmationHeading}
+
+

{MessageDesktopEditorConfirmationIntroText}

+ {isError ? ( + <> +
+
{isError}
+ + ) : null} + + + +
+ +
+ ); +}; + +export default ModalDesktopEditorOpenConfirmation; diff --git a/starsky/starsky/clientapp/src/interfaces/IEnvFeatures.ts b/starsky/starsky/clientapp/src/interfaces/IEnvFeatures.ts index 891a0afd04..647717e375 100644 --- a/starsky/starsky/clientapp/src/interfaces/IEnvFeatures.ts +++ b/starsky/starsky/clientapp/src/interfaces/IEnvFeatures.ts @@ -1,4 +1,5 @@ export interface IEnvFeatures { systemTrashEnabled: boolean; useLocalDesktop: boolean; + openEditorEnabled: boolean; } diff --git a/starsky/starsky/clientapp/src/localization/localization.json b/starsky/starsky/clientapp/src/localization/localization.json index 8b3b9ff07e..e622b625f0 100644 --- a/starsky/starsky/clientapp/src/localization/localization.json +++ b/starsky/starsky/clientapp/src/localization/localization.json @@ -239,6 +239,26 @@ "en": "Close", "nl": "Sluiten" }, + "MessageDesktopEditorOpenSingleFile": { + "en": "Open file", + "nl": "Open bestand" + }, + "MessageDesktopEditorOpenMultipleFiles": { + "en": "Open files", + "nl": "Open bestanden" + }, + "MessageDesktopEditorUnableToOpen": { + "en": "Sorry, something went wrong opening the file", + "nl": "Sorry, er iets misgegaan met het openen van het bestand" + }, + "MessageDesktopEditorConfirmationHeading": { + "en": "Do you really want to edit all of the selected photos?", + "nl": "Wil je echt alle geselecteerde foto's bewerken?" + }, + "MessageDesktopEditorConfirmationIntroText": { + "en": "This prompt is to prevent potential issues such as your computer freezing", + "nl": "Deze melding is bedoeld om te voorkomen dat er eventuele problemen optreden, zoals het vastlopen van je computer." + }, "temp1": { "en": "", "nl": "" diff --git a/starsky/starsky/clientapp/src/shared/url-query.ts b/starsky/starsky/clientapp/src/shared/url-query.ts index d6a84d0e2a..81015ab7cf 100644 --- a/starsky/starsky/clientapp/src/shared/url-query.ts +++ b/starsky/starsky/clientapp/src/shared/url-query.ts @@ -328,6 +328,14 @@ export class UrlQuery { return this.prefix + "/api/env/features?v=0.6.0-beta.2"; }; + public UrlApiDesktopEditorOpenAmountConfirmationChecker = (): string => { + return `${this.prefix}/api/desktop-editor/amount-confirmation`; + }; + + public UrlApiDesktopEditorOpen = (): string => { + return `${this.prefix}/api/desktop-editor/open`; + }; + /** * url create a zip */ diff --git a/starsky/starskytest/starsky.feature.metaupdate/Services/DeleteItemTest.cs b/starsky/starskytest/starsky.feature.metaupdate/Services/DeleteItemTest.cs index 29d2b3997c..ac6309c193 100644 --- a/starsky/starskytest/starsky.feature.metaupdate/Services/DeleteItemTest.cs +++ b/starsky/starskytest/starsky.feature.metaupdate/Services/DeleteItemTest.cs @@ -18,7 +18,7 @@ public async Task Delete_FileNotFound_Ignore() var selectorStorage = new FakeSelectorStorage(new FakeIStorage()); var deleteItem = new DeleteItem(new FakeIQuery(), new AppSettings(), selectorStorage); var result = await deleteItem.DeleteAsync("/not-found", true); - Assert.AreEqual(FileIndexItem.ExifStatus.NotFoundNotInIndex, + Assert.AreEqual(FileIndexItem.ExifStatus.NotFoundNotInIndex, result.FirstOrDefault()?.Status); } @@ -27,188 +27,210 @@ public async Task Delete_NotFoundOnDisk_Ignore() { var selectorStorage = new FakeSelectorStorage(new FakeIStorage()); var fakeQuery = - new FakeIQuery(new List {new FileIndexItem("/exist-in-db.jpg")}); - var deleteItem = new DeleteItem( fakeQuery,new AppSettings(), selectorStorage); + new FakeIQuery(new List { new FileIndexItem("/exist-in-db.jpg") }); + var deleteItem = new DeleteItem(fakeQuery, new AppSettings(), selectorStorage); var result = await deleteItem.DeleteAsync("/exist-in-db.jpg", true); - Assert.AreEqual(FileIndexItem.ExifStatus.NotFoundSourceMissing, + Assert.AreEqual(FileIndexItem.ExifStatus.NotFoundSourceMissing, result.FirstOrDefault()?.Status); } - + [TestMethod] public async Task Delete_ReadOnly_Ignored() { - var selectorStorage = new FakeSelectorStorage(new FakeIStorage(new List{"/"}, - new List{"/readonly/test.jpg"}, new List{FakeCreateAn.CreateAnImage.Bytes.ToArray()})); + var selectorStorage = new FakeSelectorStorage(new FakeIStorage(new List { "/" }, + new List { "/readonly/test.jpg" }, + new List { FakeCreateAn.CreateAnImage.Bytes.ToArray() })); var fakeQuery = - new FakeIQuery(new List {new FileIndexItem("/readonly/test.jpg")}); - var deleteItem = new DeleteItem( fakeQuery,new AppSettings{ReadOnlyFolders = new List{"/readonly"}}, selectorStorage); + new FakeIQuery(new List { new FileIndexItem("/readonly/test.jpg") }); + var deleteItem = new DeleteItem(fakeQuery, + new AppSettings { ReadOnlyFolders = new List { "/readonly" } }, + selectorStorage); var result = await deleteItem.DeleteAsync("/readonly/test.jpg", true); - - Assert.AreEqual(FileIndexItem.ExifStatus.ReadOnly, + + Assert.AreEqual(FileIndexItem.ExifStatus.ReadOnly, result.FirstOrDefault()?.Status); } - + [TestMethod] public async Task Delete_StatusNotDeleted_Ignored() { - var selectorStorage = new FakeSelectorStorage(new FakeIStorage(new List{"/"}, - new List{"/test.jpg"}, new List{FakeCreateAn.CreateAnImage.Bytes.ToArray()})); + var selectorStorage = new FakeSelectorStorage(new FakeIStorage(new List { "/" }, + new List { "/test.jpg" }, + new List { FakeCreateAn.CreateAnImage.Bytes.ToArray() })); var fakeQuery = - new FakeIQuery(new List {new FileIndexItem("/test.jpg")}); - var deleteItem = new DeleteItem( fakeQuery,new AppSettings(), selectorStorage); + new FakeIQuery(new List { new FileIndexItem("/test.jpg") }); + var deleteItem = new DeleteItem(fakeQuery, new AppSettings(), selectorStorage); var result = await deleteItem.DeleteAsync("/test.jpg", true); - - Assert.AreEqual(FileIndexItem.ExifStatus.OperationNotSupported, + + Assert.AreEqual(FileIndexItem.ExifStatus.OperationNotSupported, result.FirstOrDefault()?.Status); } - + [TestMethod] public async Task Delete_IsFileRemoved() { - var storage = new FakeIStorage(new List {"/"}, - new List {"/test.jpg"}, - new List {FakeCreateAn.CreateAnImage.Bytes.ToArray()}); + var storage = new FakeIStorage(new List { "/" }, + new List { "/test.jpg" }, + new List { FakeCreateAn.CreateAnImage.Bytes.ToArray() }); var selectorStorage = new FakeSelectorStorage(storage); var fakeQuery = - new FakeIQuery(new List {new FileIndexItem("/test.jpg") - {Tags = TrashKeyword.TrashKeywordString}}); - var deleteItem = new DeleteItem( fakeQuery,new AppSettings(), selectorStorage); + new FakeIQuery(new List + { + new FileIndexItem("/test.jpg") { Tags = TrashKeyword.TrashKeywordString } + }); + var deleteItem = new DeleteItem(fakeQuery, new AppSettings(), selectorStorage); var result = await deleteItem.DeleteAsync("/test.jpg", true); - - Assert.AreEqual(FileIndexItem.ExifStatus.Ok, + + Assert.AreEqual(FileIndexItem.ExifStatus.Ok, result.FirstOrDefault()?.Status); - + Assert.IsNull(fakeQuery.GetObjectByFilePath("/test.jpg")); Assert.IsFalse(storage.ExistFile("/test.jpg")); } - - + + [TestMethod] public async Task Delete_IsFileRemoved_WithCollection() { - var storage = new FakeIStorage(new List {"/", "/dir"}, - new List {"/dir/test.jpg"}, - new List {FakeCreateAn.CreateAnImage.Bytes.ToArray()}); + var storage = new FakeIStorage(new List { "/", "/dir" }, + new List { "/dir/test.jpg" }, + new List { FakeCreateAn.CreateAnImage.Bytes.ToArray() }); var selectorStorage = new FakeSelectorStorage(storage); var fakeQuery = - new FakeIQuery(new List { - new FileIndexItem("/dir") {IsDirectory = true, Tags = TrashKeyword.TrashKeywordString }, - - new FileIndexItem("/dir/test.jpg") {Tags = TrashKeyword.TrashKeywordString }, - new FileIndexItem("/dir/test.dng") {Tags = TrashKeyword.TrashKeywordString }} + new FakeIQuery(new List + { + new FileIndexItem("/dir") + { + IsDirectory = true, Tags = TrashKeyword.TrashKeywordString + }, + new FileIndexItem("/dir/test.jpg") + { + Tags = TrashKeyword.TrashKeywordString + }, + new FileIndexItem("/dir/test.dng") + { + Tags = TrashKeyword.TrashKeywordString + } + } ); - - var deleteItem = new DeleteItem( fakeQuery,new AppSettings(), selectorStorage); + + var deleteItem = new DeleteItem(fakeQuery, new AppSettings(), selectorStorage); var result = await deleteItem.DeleteAsync("/dir/test.jpg", true); - - Assert.AreEqual(FileIndexItem.ExifStatus.Ok, + + Assert.AreEqual(FileIndexItem.ExifStatus.Ok, result.FirstOrDefault()?.Status); - + Assert.IsNull(fakeQuery.GetObjectByFilePath("/test.jpg")); Assert.IsFalse(storage.ExistFile("/test.jpg")); - - Assert.AreEqual(FileIndexItem.ExifStatus.Ok, + + Assert.AreEqual(FileIndexItem.ExifStatus.Ok, result[1].Status); - + Assert.IsNull(fakeQuery.GetObjectByFilePath("/test.dng")); Assert.IsFalse(storage.ExistFile("/test.dng")); } - + [TestMethod] public async Task Delete_IsJsonSideCarFileRemoved() { - var storage = new FakeIStorage(new List {"/"}, - new List {"/test.jpg","/.starsky.test.jpg.json"}, - new List {FakeCreateAn.CreateAnImage.Bytes.ToArray()}); + var storage = new FakeIStorage(new List { "/" }, + new List { "/test.jpg", "/.starsky.test.jpg.json" }, + new List { FakeCreateAn.CreateAnImage.Bytes.ToArray() }); var selectorStorage = new FakeSelectorStorage(storage); var fakeQuery = - new FakeIQuery(new List {new FileIndexItem("/test.jpg") - {Tags = TrashKeyword.TrashKeywordString}}); - var deleteItem = new DeleteItem( fakeQuery,new AppSettings(), selectorStorage); + new FakeIQuery(new List + { + new FileIndexItem("/test.jpg") { Tags = TrashKeyword.TrashKeywordString } + }); + var deleteItem = new DeleteItem(fakeQuery, new AppSettings(), selectorStorage); var result = await deleteItem.DeleteAsync("/test.jpg", true); - - Assert.AreEqual(FileIndexItem.ExifStatus.Ok, + + Assert.AreEqual(FileIndexItem.ExifStatus.Ok, result.FirstOrDefault()?.Status); - + Assert.IsFalse(storage.ExistFile("/.starsky.test.jpg.json")); } - + [TestMethod] public async Task Delete_IsXmpSideCarFileRemoved() { - var storage = new FakeIStorage(new List {"/"}, - new List {"/test.dng","/test.xmp"}, - new List {FakeCreateAn.CreateAnImage.Bytes.ToArray()}); + var storage = new FakeIStorage(new List { "/" }, + new List { "/test.dng", "/test.xmp" }, + new List { FakeCreateAn.CreateAnImage.Bytes.ToArray() }); var selectorStorage = new FakeSelectorStorage(storage); var fakeQuery = - new FakeIQuery(new List {new FileIndexItem("/test.dng") - {Tags = TrashKeyword.TrashKeywordString}}); - var deleteItem = new DeleteItem( fakeQuery,new AppSettings(), selectorStorage); + new FakeIQuery(new List + { + new FileIndexItem("/test.dng") { Tags = TrashKeyword.TrashKeywordString } + }); + var deleteItem = new DeleteItem(fakeQuery, new AppSettings(), selectorStorage); var result = await deleteItem.DeleteAsync("/test.dng", true); - - Assert.AreEqual(FileIndexItem.ExifStatus.Ok, + + Assert.AreEqual(FileIndexItem.ExifStatus.Ok, result.FirstOrDefault()?.Status); - + Assert.IsFalse(storage.ExistFile("/test.xmp")); } - + [TestMethod] public async Task Delete_IsFolderRemoved() { - var storage = new FakeIStorage(new List {"/test","/"}, - new List (), - new List {FakeCreateAn.CreateAnImage.Bytes.ToArray()}); + var storage = new FakeIStorage(new List { "/test", "/" }, + new List(), + new List { FakeCreateAn.CreateAnImage.Bytes.ToArray() }); var selectorStorage = new FakeSelectorStorage(storage); var fakeQuery = - new FakeIQuery(new List {new FileIndexItem("/test") - {IsDirectory = true, Tags = TrashKeyword.TrashKeywordString}}); - var deleteItem = new DeleteItem( fakeQuery,new AppSettings(), selectorStorage); + new FakeIQuery(new List + { + new FileIndexItem("/test") + { + IsDirectory = true, Tags = TrashKeyword.TrashKeywordString + } + }); + + var deleteItem = new DeleteItem(fakeQuery, new AppSettings(), selectorStorage); var result = await deleteItem.DeleteAsync("/test", true); - - Assert.AreEqual(FileIndexItem.ExifStatus.Ok, + + Assert.AreEqual(FileIndexItem.ExifStatus.Ok, result.FirstOrDefault()?.Status); - + Assert.IsNull(fakeQuery.GetObjectByFilePath("/test")); Assert.IsFalse(storage.ExistFolder("/test")); } - + [TestMethod] public async Task Delete_IsFolderRemoved_IncludingChildFolders() { var storage = new FakeIStorage( - new List - { - "/test", - "/", - "/test/child_folder" - }, - new List {"/test/child_folder/i.jpg"}, - new List - { - FakeCreateAn.CreateAnImage.Bytes.ToArray() - }); + new List { "/test", "/", "/test/child_folder" }, + new List { "/test/child_folder/i.jpg" }, + new List { FakeCreateAn.CreateAnImage.Bytes.ToArray() }); var selectorStorage = new FakeSelectorStorage(storage); var fakeQuery = - new FakeIQuery(new List { - new FileIndexItem("/test"){IsDirectory = true, Tags = TrashKeyword.TrashKeywordString}, - new FileIndexItem("/test/child_folder"){IsDirectory = true}, - new FileIndexItem("/test/child_folder/2"){IsDirectory = true} + new FakeIQuery(new List + { + new FileIndexItem("/test") + { + IsDirectory = true, Tags = TrashKeyword.TrashKeywordString + }, + new FileIndexItem("/test/child_folder") { IsDirectory = true }, + new FileIndexItem("/test/child_folder/2") { IsDirectory = true } }); - var deleteItem = new DeleteItem( fakeQuery,new AppSettings(), selectorStorage); + var deleteItem = new DeleteItem(fakeQuery, new AppSettings(), selectorStorage); var result = await deleteItem.DeleteAsync("/test", true); - - Assert.AreEqual(FileIndexItem.ExifStatus.Ok, + + Assert.AreEqual(FileIndexItem.ExifStatus.Ok, result.FirstOrDefault()?.Status); - - Assert.AreEqual(0,fakeQuery.GetAllFolders().Count); + + Assert.AreEqual(0, fakeQuery.GetAllFolders().Count); Assert.IsNull(fakeQuery.GetObjectByFilePath("/test")); Assert.IsNull(fakeQuery.GetObjectByFilePath("/test/child_folder")); Assert.IsNull(fakeQuery.GetObjectByFilePath("/test/child_folder/2")); @@ -218,18 +240,27 @@ public async Task Delete_IsFolderRemoved_IncludingChildFolders() [TestMethod] public async Task Delete_DirectoryWithChildItems_CollectionsOn() { - var storage = new FakeIStorage(new List {"/test","/"}, - new List {"/test/image.jpg", "/test/image.dng"}, - new List {FakeCreateAn.CreateAnImage.Bytes.ToArray(), - FakeCreateAn.CreateAnImage.Bytes.ToArray()}); + var storage = new FakeIStorage(new List { "/test", "/" }, + new List { "/test/image.jpg", "/test/image.dng" }, + new List + { + FakeCreateAn.CreateAnImage.Bytes.ToArray(), + FakeCreateAn.CreateAnImage.Bytes.ToArray() + }); var selectorStorage = new FakeSelectorStorage(storage); - + var fakeQuery = - new FakeIQuery(new List {new FileIndexItem("/test") - {IsDirectory = true, Tags = TrashKeyword.TrashKeywordString}, new FileIndexItem("/test/image.jpg"), - new FileIndexItem("/test/image.dng")}); - - var deleteItem = new DeleteItem( fakeQuery,new AppSettings(), selectorStorage); + new FakeIQuery(new List + { + new FileIndexItem("/test") + { + IsDirectory = true, Tags = TrashKeyword.TrashKeywordString + }, + new FileIndexItem("/test/image.jpg"), + new FileIndexItem("/test/image.dng") + }); + + var deleteItem = new DeleteItem(fakeQuery, new AppSettings(), selectorStorage); var result = await deleteItem.DeleteAsync("/test", true); Assert.AreEqual(3, result.Count); @@ -240,26 +271,31 @@ public async Task Delete_DirectoryWithChildItems_CollectionsOn() Assert.AreEqual(0, storage.GetAllFilesInDirectoryRecursive("/").Count()); Assert.AreEqual(0, fakeQuery.GetAllRecursive("/").Count); } - + [TestMethod] public async Task Delete_DirectoryWithChildItems_CollectionsOff() { - var storage = new FakeIStorage(new List {"/test","/"}, - new List {"/test/image.jpg", "/test/image.dng"}, - new List {FakeCreateAn.CreateAnImage.Bytes.ToArray(), - FakeCreateAn.CreateAnImage.Bytes.ToArray()}); + var storage = new FakeIStorage(new List { "/test", "/" }, + new List { "/test/image.jpg", "/test/image.dng" }, + new List + { + FakeCreateAn.CreateAnImage.Bytes.ToArray(), + FakeCreateAn.CreateAnImage.Bytes.ToArray() + }); var selectorStorage = new FakeSelectorStorage(storage); - + var fakeQuery = - new FakeIQuery(new List { - new FileIndexItem("/test") { - IsDirectory = true, - Tags = TrashKeyword.TrashKeywordString - }, - new FileIndexItem("/test/image.jpg"), - new FileIndexItem("/test/image.dng")}); - - var deleteItem = new DeleteItem( fakeQuery,new AppSettings(), selectorStorage); + new FakeIQuery(new List + { + new FileIndexItem("/test") + { + IsDirectory = true, Tags = TrashKeyword.TrashKeywordString + }, + new FileIndexItem("/test/image.jpg"), + new FileIndexItem("/test/image.dng") + }); + + var deleteItem = new DeleteItem(fakeQuery, new AppSettings(), selectorStorage); var result = await deleteItem.DeleteAsync("/test", false); Assert.AreEqual(3, result.Count); @@ -268,28 +304,33 @@ public async Task Delete_DirectoryWithChildItems_CollectionsOff() Assert.AreEqual("/test/image.dng", result[2].FilePath); Assert.AreEqual(0, storage.GetAllFilesInDirectoryRecursive("/").Count()); - Assert.AreEqual(0, (await fakeQuery.GetAllRecursiveAsync("/")).Count); + Assert.AreEqual(0, ( await fakeQuery.GetAllRecursiveAsync() ).Count); } [TestMethod] public async Task Delete_ChildDirectories() { - var storage = new FakeIStorage(new List {"/test", "/", "/test/child", "/test/child/child"}, - new List (), + var storage = new FakeIStorage( + new List { "/test", "/", "/test/child", "/test/child/child" }, + new List(), new List()); var selectorStorage = new FakeSelectorStorage(storage); - + var fakeQuery = - new FakeIQuery(new List { - new FileIndexItem("/test") {IsDirectory = true, Tags = TrashKeyword.TrashKeywordString}, - new FileIndexItem("/test/child") {IsDirectory = true}, - new FileIndexItem("/test/child/child") {IsDirectory = true}, + new FakeIQuery(new List + { + new FileIndexItem("/test") + { + IsDirectory = true, Tags = TrashKeyword.TrashKeywordString + }, + new FileIndexItem("/test/child") { IsDirectory = true }, + new FileIndexItem("/test/child/child") { IsDirectory = true }, }); - - var deleteItem = new DeleteItem( fakeQuery,new AppSettings(), selectorStorage); + + var deleteItem = new DeleteItem(fakeQuery, new AppSettings(), selectorStorage); var result = await deleteItem.DeleteAsync("/test", false); - + Assert.AreEqual(3, result.Count); Assert.AreEqual("/test", result[0].FilePath); Assert.AreEqual("/test/child", result[1].FilePath);