From cb72b5365329ee31fcfefd1a6f229834a7c212aa Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Wed, 15 Dec 2021 13:50:40 +0100 Subject: [PATCH] Refactoring to message listeners --- package.json | 9 ++ src/commands/Dashboard.ts | 120 ++++------------- src/commands/Folders.ts | 5 +- src/constants/Extension.ts | 1 + .../components/Contents/Contents.tsx | 22 ++-- .../components/Contents/Item.tsx | 7 +- .../components/Contents/List.tsx | 9 +- src/dashboardWebView/components/Dashboard.tsx | 18 ++- .../components/Header/Breadcrumb.tsx | 4 +- .../components/Header/Header.tsx | 14 +- .../components/Header/Sorting.tsx | 14 +- .../components/Header/ViewSwitch.tsx | 9 +- .../components/Media/Media.tsx | 124 +++++++++--------- .../components/Media/Pagination.tsx | 52 +++++--- src/dashboardWebView/hooks/useMessages.tsx | 8 +- .../models/{ViewType.ts => NavigationType.ts} | 2 +- src/dashboardWebView/models/Settings.ts | 10 +- src/dashboardWebView/models/index.ts | 2 +- .../state/atom/DashboardViewAtom.ts | 6 +- src/extension.ts | 10 +- src/helpers/DashboardSettings.ts | 7 +- src/helpers/Logger.ts | 5 +- src/helpers/MediaHelpers.ts | 18 ++- src/helpers/MediaLibrary.ts | 7 +- src/helpers/Notifications.ts | 4 + src/listeners/BaseListener.ts | 4 +- src/listeners/DashboardListener.ts | 2 +- src/listeners/ExtensionListener.ts | 14 ++ src/listeners/MediaListener.ts | 27 +++- src/listeners/SettingsListener.ts | 29 +++- 30 files changed, 303 insertions(+), 260 deletions(-) rename src/dashboardWebView/models/{ViewType.ts => NavigationType.ts} (58%) diff --git a/package.json b/package.json index c1574b11..a4400991 100644 --- a/package.json +++ b/package.json @@ -797,6 +797,15 @@ "light": "/assets/icons/frontmatter-small-light.svg" } }, + { + "command": "frontMatter.dashboard.media", + "title": "Open media dashboard", + "category": "Front matter", + "icon": { + "dark": "/assets/icons/frontmatter-small-dark.svg", + "light": "/assets/icons/frontmatter-small-light.svg" + } + }, { "command": "frontMatter.dashboard.close", "title": "Close dashboard", diff --git a/src/commands/Dashboard.ts b/src/commands/Dashboard.ts index 1e79a89e..3ffb0a72 100644 --- a/src/commands/Dashboard.ts +++ b/src/commands/Dashboard.ts @@ -1,37 +1,19 @@ -import { SETTINGS_CONTENT_STATIC_FOLDER, SETTING_DATE_FIELD, SETTING_SEO_DESCRIPTION_FIELD, SETTINGS_DASHBOARD_OPENONSTART, SETTINGS_DASHBOARD_MEDIA_SNIPPET, SETTING_TAXONOMY_CONTENT_TYPES, DefaultFields, HOME_PAGE_NAVIGATION_ID, ExtensionState, COMMAND_NAME, SETTINGS_FRAMEWORK_ID, SETTINGS_CONTENT_DRAFT_FIELD, SETTINGS_CONTENT_SORTING, CONTEXT, SETTING_CUSTOM_SCRIPTS, SETTINGS_CONTENT_SORTING_DEFAULT, SETTINGS_MEDIA_SORTING_DEFAULT } from '../constants'; -import { ArticleHelper } from './../helpers/ArticleHelper'; -import { basename, dirname, extname, join, parse } from "path"; -import { existsSync, readdirSync, statSync, unlinkSync, writeFileSync } from "fs"; -import { commands, Uri, ViewColumn, Webview, WebviewPanel, window, workspace, env, Position } from "vscode"; -import { Settings as SettingsHelper } from '../helpers'; -import { CustomScript as ICustomScript, DraftField, Framework, ScriptType, SortingSetting, SortOrder, SortType, TaxonomyType } from '../models'; -import { Folders } from './Folders'; +import { PagesListener } from './../listeners/PagesListener'; +import { ExtensionListener } from './../listeners/ExtensionListener'; +import { SETTINGS_DASHBOARD_OPENONSTART, CONTEXT } from '../constants'; +import { join } from "path"; +import { commands, Uri, ViewColumn, Webview, WebviewPanel, window } from "vscode"; +import { Logger, Settings as SettingsHelper } from '../helpers'; import { DashboardCommand } from '../dashboardWebView/DashboardCommand'; -import { DashboardMessage } from '../dashboardWebView/DashboardMessage'; -import { Page } from '../dashboardWebView/models/Page'; -import { openFileInEditor } from '../helpers/openFileInEditor'; -import { Template } from './Template'; -import { Notifications } from '../helpers/Notifications'; import { Extension } from '../helpers/Extension'; -import { EditorHelper, WebviewHelper } from '@estruyf/vscode'; -import { MediaInfo, MediaPaths } from './../models/MediaPaths'; -import { decodeBase64Image } from '../helpers/decodeBase64Image'; +import { WebviewHelper } from '@estruyf/vscode'; import { DashboardData } from '../models/DashboardData'; import { ExplorerView } from '../explorerView/ExplorerView'; import { MediaLibrary } from '../helpers/MediaLibrary'; -import { parseWinPath } from '../helpers/parseWinPath'; -import { DateHelper } from '../helpers/DateHelper'; -import { FrameworkDetector } from '../helpers/FrameworkDetector'; -import { ContentType } from '../helpers/ContentType'; -import { SortingOption } from '../dashboardWebView/models'; -import { Sorting } from '../helpers/Sorting'; -import imageSize from 'image-size'; -import { CustomScript } from '../helpers/CustomScript'; -import { DashboardListener, SettingsListener } from '../listeners'; +import { DashboardListener, MediaListener, SettingsListener } from '../listeners'; export class Dashboard { private static webview: WebviewPanel | null = null; - private static mediaLib: MediaLibrary; private static _viewData: DashboardData | undefined; private static isDisposed: boolean = true; @@ -53,12 +35,12 @@ export class Dashboard { * Open or reveal the dashboard */ public static async open(data?: DashboardData) { - this.mediaLib = MediaLibrary.getInstance(); + MediaLibrary.getInstance(); Dashboard._viewData = data; if (Dashboard.isOpen) { - Dashboard.reveal(); + Dashboard.reveal(!!data); } else { Dashboard.create(); } @@ -76,9 +58,13 @@ export class Dashboard { /** * Reveal the dashboard if it is open */ - public static reveal() { + public static reveal(hasData: boolean = false) { if (Dashboard.webview) { Dashboard.webview.reveal(); + + if (hasData) { + Dashboard.postWebviewMessage({ command: DashboardCommand.viewData, data: Dashboard.viewData }); + } } } @@ -112,7 +98,8 @@ export class Dashboard { 'FrontMatter Dashboard', ViewColumn.One, { - enableScripts: true + enableScripts: true, + retainContextWhenHidden: true } ); @@ -130,6 +117,8 @@ export class Dashboard { Dashboard._viewData = undefined; const panel = ExplorerView.getInstance(extensionUri); panel.getMediaSelection(); + + Dashboard.postWebviewMessage({ command: DashboardCommand.viewData, data: null }); } await commands.executeCommand('setContext', CONTEXT.isDashboardOpen, this.webview?.visible); @@ -148,37 +137,13 @@ export class Dashboard { }); Dashboard.webview.webview.onDidReceiveMessage(async (msg) => { + Logger.info(`Receiving message from webview: ${msg.command}`); + DashboardListener.process(msg); - - - - switch(msg.command) { - - - - - - case DashboardMessage.insertPreviewImage: - Dashboard.insertImage(msg?.data); - break; - case DashboardMessage.updateMediaMetadata: - Dashboard.updateMediaMetadata(msg?.data); - break; - case DashboardMessage.createMediaFolder: - await commands.executeCommand(COMMAND_NAME.createFolder, msg?.data); - break; - case DashboardMessage.setFramework: - Dashboard.setFramework(msg?.data); - break; - case DashboardMessage.runCustomScript: - CustomScript.run(msg?.data?.script, msg?.data?.path); - break; - case DashboardMessage.setState: - if (msg?.data?.key && msg?.data?.value) { - Extension.getInstance().setState(msg?.data?.key, msg?.data?.value, "workspace"); - } - break; - } + ExtensionListener.process(msg); + MediaListener.process(msg); + PagesListener.process(msg); + SettingsListener.process(msg); }); } @@ -190,11 +155,6 @@ export class Dashboard { return Dashboard.webview?.webview; } - public static switchFolder(folderPath: string) { - Dashboard.resetMedia(); - Dashboard.getMedia(0, folderPath); - } - /** * Post data to the dashboard * @param msg @@ -208,36 +168,6 @@ export class Dashboard { Dashboard.webview?.webview.postMessage(msg); } } - - /** - * Set the current site-generator or framework + related settings - * @param frameworkId - */ - private static setFramework(frameworkId: string | null) { - SettingsHelper.update(SETTINGS_FRAMEWORK_ID, frameworkId, true); - - if (frameworkId) { - const allFrameworks = FrameworkDetector.getAll(); - const framework = allFrameworks.find((f: Framework) => f.name === frameworkId); - if (framework) { - SettingsHelper.update(SETTINGS_CONTENT_STATIC_FOLDER, framework.static, true); - } else { - SettingsHelper.update(SETTINGS_CONTENT_STATIC_FOLDER, "", true); - } - } - } - - /** - * Update the metadata of the selected file - */ - private static async updateMediaMetadata({ file, filename, page, folder, ...metadata }: { file:string; filename:string; page: number; folder: string | null; metadata: any; }) { - Dashboard.mediaLib.set(file, metadata); - - // Check if filename needs to be updated - Dashboard.mediaLib.updateFilename(file, filename); - - Dashboard.getMedia(page || 0, folder || ""); - } /** * Retrieve the webview HTML contents diff --git a/src/commands/Folders.ts b/src/commands/Folders.ts index 1b0c45ce..179fc4e1 100644 --- a/src/commands/Folders.ts +++ b/src/commands/Folders.ts @@ -11,6 +11,8 @@ import { existsSync, mkdirSync } from 'fs'; import { format } from 'date-fns'; import { Dashboard } from './Dashboard'; import { parseWinPath } from '../helpers/parseWinPath'; +import { MediaHelpers } from '../helpers/MediaHelpers'; +import { MediaListener } from '../listeners'; export const WORKSPACE_PLACEHOLDER = `[[workspace]]`; @@ -62,7 +64,8 @@ export class Folders { } if (Dashboard.isOpen) { - Dashboard.switchFolder(folderName); + MediaHelpers.resetMedia(); + MediaListener.sendMediaFiles(0, folderName); } } diff --git a/src/constants/Extension.ts b/src/constants/Extension.ts index 001311fa..0afeff0d 100644 --- a/src/constants/Extension.ts +++ b/src/constants/Extension.ts @@ -28,6 +28,7 @@ export const COMMAND_NAME = { collapseSections: getCommandName("collapseSections"), preview: getCommandName("preview"), dashboard: getCommandName("dashboard"), + dashboardMedia: getCommandName("dashboard.media"), dashboardClose: getCommandName("dashboard.close"), promote: getCommandName("promoteSettings"), insertImage: getCommandName("insertImage"), diff --git a/src/dashboardWebView/components/Contents/Contents.tsx b/src/dashboardWebView/components/Contents/Contents.tsx index b2450786..16c5b56a 100644 --- a/src/dashboardWebView/components/Contents/Contents.tsx +++ b/src/dashboardWebView/components/Contents/Contents.tsx @@ -20,19 +20,17 @@ export const Contents: React.FunctionComponent = ({pages, loadin const pageFolders = [...new Set(pageItems.map(page => page.fmFolder))]; return ( -
-
-
+
+
-
- { loading ? : } -
- - +
+ { loading ? : }
-
+ + + ); }; \ No newline at end of file diff --git a/src/dashboardWebView/components/Contents/Item.tsx b/src/dashboardWebView/components/Contents/Item.tsx index 08479f58..f9006bb2 100644 --- a/src/dashboardWebView/components/Contents/Item.tsx +++ b/src/dashboardWebView/components/Contents/Item.tsx @@ -3,11 +3,12 @@ import { useRecoilValue } from 'recoil'; import { MarkdownIcon } from '../../../panelWebView/components/Icons/MarkdownIcon'; import { DashboardMessage } from '../../DashboardMessage'; import { Page } from '../../models/Page'; -import { SettingsSelector, ViewSelector, ViewType } from '../../state'; +import { SettingsSelector, ViewSelector } from '../../state'; import { DateField } from '../DateField'; import { Status } from '../Status'; import { Messenger } from '@estruyf/vscode/dist/client'; import useContentType from '../../../hooks/useContentType'; +import { DashboardViewType } from '../../models'; export interface IItemProps extends Page {} @@ -22,7 +23,7 @@ export const Item: React.FunctionComponent = ({ fmFilePath, date, ti Messenger.send(DashboardMessage.openFile, fmFilePath); }; - if (view === ViewType.Grid) { + if (view === DashboardViewType.Grid) { return (
  • ); - } else if (view === ViewType.List) { + } else if (view === DashboardViewType.List) { return (
  • - { - view === ViewType.Contents && ( + view === NavigationType.Contents && ( <>
    @@ -112,14 +112,14 @@ export const Header: React.FunctionComponent = ({totalPages, folde - +
    ) } { - view === ViewType.Media && ( + view === NavigationType.Media && ( <> diff --git a/src/dashboardWebView/components/Header/Sorting.tsx b/src/dashboardWebView/components/Header/Sorting.tsx index bd136ab7..d5d4d9f8 100644 --- a/src/dashboardWebView/components/Header/Sorting.tsx +++ b/src/dashboardWebView/components/Header/Sorting.tsx @@ -6,14 +6,14 @@ import { ExtensionState } from '../../../constants'; import { SortOrder, SortType } from '../../../models'; import { SortOption } from '../../constants/SortOption'; import { DashboardMessage } from '../../DashboardMessage'; -import { ViewType } from '../../models'; +import { NavigationType } from '../../models'; import { SortingOption } from '../../models/SortingOption'; import { SearchSelector, SettingsSelector, SortingAtom } from '../../state'; import { MenuButton, MenuItem, MenuItems } from '../Menu'; export interface ISortingProps { disableCustomSorting?: boolean; - view: ViewType; + view: NavigationType; } export const sortOptions: SortingOption[] = [ @@ -30,7 +30,7 @@ export const Sorting: React.FunctionComponent = ({disableCustomSo const updateSorting = (value: SortingOption) => { Messenger.send(DashboardMessage.setState, { - key: `${view === ViewType.Contents ? ExtensionState.Dashboard.Contents.Sorting : ExtensionState.Dashboard.Media.Sorting}`, + key: `${view === NavigationType.Contents ? ExtensionState.Dashboard.Contents.Sorting : ExtensionState.Dashboard.Media.Sorting}`, value: value }); @@ -50,16 +50,16 @@ export const Sorting: React.FunctionComponent = ({disableCustomSo let crntSortingOption = crntSorting; if (!crntSortingOption) { - if (view === ViewType.Contents) { + if (view === NavigationType.Contents) { crntSortingOption = settings?.dashboardState?.contents?.sorting || null; - } else if (view === ViewType.Media) { + } else if (view === NavigationType.Media) { crntSortingOption = settings?.dashboardState?.media?.sorting || null; } if (crntSortingOption === null) { - if (view === ViewType.Contents && settings?.dashboardState.contents.defaultSorting) { + if (view === NavigationType.Contents && settings?.dashboardState.contents.defaultSorting) { crntSortingOption = allOptions.find(f => f.id === settings?.dashboardState.contents.defaultSorting) || null; - } else if (view === ViewType.Media && settings?.dashboardState.contents.defaultSorting) { + } else if (view === NavigationType.Media && settings?.dashboardState.contents.defaultSorting) { crntSortingOption = allOptions.find(f => f.id === settings?.dashboardState.contents.defaultSorting) || null; } } diff --git a/src/dashboardWebView/components/Header/ViewSwitch.tsx b/src/dashboardWebView/components/Header/ViewSwitch.tsx index e45dd6a9..d0e441b3 100644 --- a/src/dashboardWebView/components/Header/ViewSwitch.tsx +++ b/src/dashboardWebView/components/Header/ViewSwitch.tsx @@ -1,9 +1,10 @@ import * as React from 'react'; import { useRecoilState, useRecoilValue } from 'recoil'; -import { ViewAtom, ViewType, SettingsSelector } from '../../state'; +import { ViewAtom, SettingsSelector } from '../../state'; import { ViewGridIcon, ViewListIcon } from '@heroicons/react/solid'; import { Messenger } from '@estruyf/vscode/dist/client'; import { DashboardMessage } from '../../DashboardMessage'; +import { DashboardViewType } from '../../models'; export interface IViewSwitchProps {} @@ -12,7 +13,7 @@ export const ViewSwitch: React.FunctionComponent = (props: Rea const settings = useRecoilValue(SettingsSelector); const toggleView = () => { - const newView = view === ViewType.Grid ? ViewType.List : ViewType.Grid; + const newView = view === DashboardViewType.Grid ? DashboardViewType.List : DashboardViewType.Grid; setView(newView); Messenger.send(DashboardMessage.setPageViewType, newView); }; @@ -25,11 +26,11 @@ export const ViewSwitch: React.FunctionComponent = (props: Rea return (
    - - diff --git a/src/dashboardWebView/components/Media/Media.tsx b/src/dashboardWebView/components/Media/Media.tsx index 7fa0c634..f4c0d9d0 100644 --- a/src/dashboardWebView/components/Media/Media.tsx +++ b/src/dashboardWebView/components/Media/Media.tsx @@ -73,75 +73,73 @@ export const Media: React.FunctionComponent = (props: React.PropsWi }, ['']); return ( -
    -
    -
    +
    +
    -
    - - { - viewData?.data?.filePath && ( -
    -

    Select the image you want to use for your article.

    -

    You can also drag and drop images from your desktop and select that once uploaded.

    -
    - ) - } - - { - isDragActive && ( -
    - -

    - {selectedFolder ? `Upload to ${selectedFolder}` : `No folder selected, files you drop will be added to the ${settings?.staticFolder || "public"} folder.`} -

    -
    - ) - } - - { - (media.length === 0 && folders.length === 0 && !loading) && ( -
    -
    - - -

    No media files to show. You can drag & drop new files.

    -
    -
    - ) - } - - { - folders && folders.length > 0 && ( -
    - - { - folders && folders.map((folder) => ( - - )) - } - -
    - ) - } - - - { - media.map((file) => ( - - )) - } - -
    +
    { - loading && ( ) + viewData?.data?.filePath && ( +
    +

    Select the image you want to use for your article.

    +

    You can also drag and drop images from your desktop and select that once uploaded.

    +
    + ) + } + + { + isDragActive && ( +
    + +

    + {selectedFolder ? `Upload to ${selectedFolder}` : `No folder selected, files you drop will be added to the ${settings?.staticFolder || "public"} folder.`} +

    +
    + ) } - + { + (media.length === 0 && folders.length === 0 && !loading) && ( +
    +
    + + +

    No media files to show. You can drag & drop new files.

    +
    +
    + ) + } - + { + folders && folders.length > 0 && ( +
    + + { + folders && folders.map((folder) => ( + + )) + } + +
    + ) + } + + + { + media.map((file) => ( + + )) + } +
    -
    + + { + loading && ( ) + } + + + + +
    ); }; \ No newline at end of file diff --git a/src/dashboardWebView/components/Media/Pagination.tsx b/src/dashboardWebView/components/Media/Pagination.tsx index 28fbe262..5f56fc0e 100644 --- a/src/dashboardWebView/components/Media/Pagination.tsx +++ b/src/dashboardWebView/components/Media/Pagination.tsx @@ -3,9 +3,11 @@ import { Messenger } from '@estruyf/vscode/dist/client'; import { RefreshIcon } from '@heroicons/react/outline'; import * as React from 'react'; import { useRecoilState, useRecoilValue } from 'recoil'; +import { useDebounce } from '../../../hooks/useDebounce'; +import { usePrevious } from '../../../panelWebView/hooks/usePrevious'; import { DashboardCommand } from '../../DashboardCommand'; import { DashboardMessage } from '../../DashboardMessage'; -import { LoadingAtom, MediaTotalSelector, PageAtom, SelectedMediaFolderSelector, SortingSelector } from '../../state'; +import { LoadingAtom, MediaTotalSelector, PageAtom, SelectedMediaFolderSelector, SettingsSelector, SortingSelector } from '../../state'; import { FolderCreation } from './FolderCreation'; import { LIMIT } from './Media'; import { PaginationButton } from './PaginationButton'; @@ -13,12 +15,16 @@ import { PaginationButton } from './PaginationButton'; export interface IPaginationProps {} export const Pagination: React.FunctionComponent = ({}: React.PropsWithChildren) => { + const [ lastUpdated, setLastUpdated ] = React.useState(null); const selectedFolder = useRecoilValue(SelectedMediaFolderSelector); const crntSorting = useRecoilValue(SortingSelector); const totalMedia = useRecoilValue(MediaTotalSelector); const [ , setLoading ] = useRecoilState(LoadingAtom); const [ page, setPage ] = useRecoilState(PageAtom); - + const settings = useRecoilValue(SettingsSelector); + const debounceGetMedia = useDebounce(lastUpdated, 200); + const prevSelectedFolder = usePrevious(selectedFolder); + const totalPages = Math.ceil(totalMedia / LIMIT) - 1; const getTotalPage = () => { @@ -61,35 +67,39 @@ export const Pagination: React.FunctionComponent = ({}: React. } React.useEffect(() => { - setLoading(true); - Messenger.send(DashboardMessage.getMedia, { - page, - folder: selectedFolder || '', - sorting: crntSorting - }); + setLastUpdated(new Date().getTime().toString()); }, [page]); React.useEffect(() => { - setLoading(true); - Messenger.send(DashboardMessage.getMedia, { - page: 0, - folder: selectedFolder || '', - sorting: crntSorting - }); - setPage(0); + if (prevSelectedFolder !== null || settings?.dashboardState?.media.selectedFolder !== selectedFolder) { + setLoading(true); + setPage(0); + setLastUpdated(new Date().getTime().toString()); + } }, [selectedFolder]); React.useEffect(() => { - setLoading(true); - Messenger.send(DashboardMessage.getMedia, { - page, - folder: selectedFolder || '', - sorting: crntSorting - }); + setLastUpdated(new Date().getTime().toString()); }, [crntSorting]); + React.useEffect(() => { + if (debounceGetMedia) { + setLoading(true); + + Messenger.send(DashboardMessage.getMedia, { + page, + folder: selectedFolder || '', + sorting: crntSorting + }); + } + }, [debounceGetMedia]); + React.useEffect(() => { Messenger.listen(mediaUpdate); + + return () => { + Messenger.unlisten(mediaUpdate); + } }, []); return ( diff --git a/src/dashboardWebView/hooks/useMessages.tsx b/src/dashboardWebView/hooks/useMessages.tsx index 759cd224..fe696d37 100644 --- a/src/dashboardWebView/hooks/useMessages.tsx +++ b/src/dashboardWebView/hooks/useMessages.tsx @@ -6,7 +6,7 @@ import { Page } from '../models/Page'; import { DashboardViewAtom, SettingsAtom, ViewDataAtom } from '../state'; import { Messenger } from '@estruyf/vscode/dist/client'; import { EventData } from '@estruyf/vscode/dist/models'; -import { ViewType } from '../models'; +import { NavigationType } from '../models'; export default function useMessages() { const [loading, setLoading] = useState(false); @@ -22,8 +22,10 @@ export default function useMessages() { break; case DashboardCommand.viewData: setViewData(message.data.data); - if (message.data.data?.type === ViewType.Media) { - setView(ViewType.Media); + if (message.data.data?.type === NavigationType.Media) { + setView(NavigationType.Media); + } else if (message.data.data?.type === NavigationType.Contents) { + setView(NavigationType.Contents); } break; case DashboardCommand.settings: diff --git a/src/dashboardWebView/models/ViewType.ts b/src/dashboardWebView/models/NavigationType.ts similarity index 58% rename from src/dashboardWebView/models/ViewType.ts rename to src/dashboardWebView/models/NavigationType.ts index da62bbc2..da02c4f4 100644 --- a/src/dashboardWebView/models/ViewType.ts +++ b/src/dashboardWebView/models/NavigationType.ts @@ -1,4 +1,4 @@ -export enum ViewType { +export enum NavigationType { Contents = "contents", Media = "media" } \ No newline at end of file diff --git a/src/dashboardWebView/models/Settings.ts b/src/dashboardWebView/models/Settings.ts index 65120692..596b8f44 100644 --- a/src/dashboardWebView/models/Settings.ts +++ b/src/dashboardWebView/models/Settings.ts @@ -1,8 +1,8 @@ import { VersionInfo } from '../../models/VersionInfo'; -import { ViewType } from '../state'; import { ContentFolder } from '../../models/ContentFolder'; import { ContentType, CustomScript, DraftField, Framework, SortingSetting } from '../../models'; import { SortingOption } from './SortingOption'; +import { DashboardViewType } from '.'; export interface Settings { beta: boolean; @@ -14,7 +14,7 @@ export interface Settings { categories: string[]; openOnStart: boolean | null; versionInfo: VersionInfo; - pageViewType: ViewType | undefined; + pageViewType: DashboardViewType | undefined; mediaSnippet: string[]; contentTypes: ContentType[]; contentFolders: ContentFolder[]; @@ -28,10 +28,14 @@ export interface Settings { export interface DashboardState { contents: ViewState; - media: ViewState; + media: MediaViewState; } export interface ViewState { sorting: SortingOption | null | undefined; defaultSorting: string | null | undefined; +} + +export interface MediaViewState extends ViewState { + selectedFolder: string | null | undefined; } \ No newline at end of file diff --git a/src/dashboardWebView/models/index.ts b/src/dashboardWebView/models/index.ts index 98f04914..06a24ac9 100644 --- a/src/dashboardWebView/models/index.ts +++ b/src/dashboardWebView/models/index.ts @@ -1,6 +1,6 @@ export * from './DashboardViewType'; +export * from './NavigationType'; export * from './Page'; export * from './Settings'; export * from './SortingOption'; export * from './Status'; -export * from './ViewType'; diff --git a/src/dashboardWebView/state/atom/DashboardViewAtom.ts b/src/dashboardWebView/state/atom/DashboardViewAtom.ts index 633d0fb7..94390e1d 100644 --- a/src/dashboardWebView/state/atom/DashboardViewAtom.ts +++ b/src/dashboardWebView/state/atom/DashboardViewAtom.ts @@ -1,7 +1,7 @@ import { atom } from 'recoil'; -import { ViewType } from '../../models'; +import { NavigationType } from '../../models'; -export const DashboardViewAtom = atom({ +export const DashboardViewAtom = atom({ key: 'DashboardViewAtom', - default: ViewType.Contents + default: NavigationType.Contents }); \ No newline at end of file diff --git a/src/extension.ts b/src/extension.ts index ac0b662d..3b46f7f5 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -45,7 +45,15 @@ export async function activate(context: vscode.ExtensionContext) { // Pages dashboard Dashboard.init(); subscriptions.push(vscode.commands.registerCommand(COMMAND_NAME.dashboard, (data?: DashboardData) => { - Dashboard.open(data); + if (!data) { + Dashboard.open({ type: "contents" }); + } else { + Dashboard.open(data); + } + })); + + subscriptions.push(vscode.commands.registerCommand(COMMAND_NAME.dashboardMedia, (data?: DashboardData) => { + Dashboard.open({ type: "media" }); })); subscriptions.push(vscode.commands.registerCommand(COMMAND_NAME.dashboardClose, (data?: DashboardData) => { diff --git a/src/helpers/DashboardSettings.ts b/src/helpers/DashboardSettings.ts index 05ebfa91..35bce516 100644 --- a/src/helpers/DashboardSettings.ts +++ b/src/helpers/DashboardSettings.ts @@ -1,7 +1,7 @@ import { Folders } from "../commands/Folders"; import { Template } from "../commands/Template"; import { ExtensionState, SETTINGS_CONTENT_DRAFT_FIELD, SETTINGS_CONTENT_SORTING, SETTINGS_CONTENT_SORTING_DEFAULT, SETTINGS_CONTENT_STATIC_FOLDER, SETTINGS_DASHBOARD_MEDIA_SNIPPET, SETTINGS_DASHBOARD_OPENONSTART, SETTINGS_FRAMEWORK_ID, SETTINGS_MEDIA_SORTING_DEFAULT, SETTING_CUSTOM_SCRIPTS, SETTING_TAXONOMY_CONTENT_TYPES } from "../constants"; -import { DashboardViewType, SortingOption } from "../dashboardWebView/models"; +import { DashboardViewType, SortingOption, Settings as ISettings } from "../dashboardWebView/models"; import { CustomScript, DraftField, ScriptType, SortingSetting, TaxonomyType } from "../models"; import { Extension } from "./Extension"; import { FrameworkDetector } from "./FrameworkDetector"; @@ -41,9 +41,10 @@ export class DashboardSettings { }, media: { sorting: await ext.getState(ExtensionState.Dashboard.Media.Sorting, "workspace"), - defaultSorting: Settings.get(SETTINGS_MEDIA_SORTING_DEFAULT) + defaultSorting: Settings.get(SETTINGS_MEDIA_SORTING_DEFAULT), + selectedFolder: await ext.getState(ExtensionState.SelectedFolder, "workspace") } } - } as Settings + } as ISettings } } \ No newline at end of file diff --git a/src/helpers/Logger.ts b/src/helpers/Logger.ts index 6ea571c1..576a769e 100644 --- a/src/helpers/Logger.ts +++ b/src/helpers/Logger.ts @@ -1,5 +1,6 @@ import { Extension } from './Extension'; import { OutputChannel, window } from 'vscode'; +import { format } from 'date-fns'; export class Logger { private static instance: Logger; @@ -17,11 +18,11 @@ export class Logger { return Logger.instance; } - public static info(message: string): void { + public static info(message: string, type: "INFO" | "WARNING" | "ERROR" = "INFO"): void { if (!Logger.channel) { Logger.getInstance(); } - Logger.channel?.appendLine(message); + Logger.channel?.appendLine(`["${type}" - ${format(new Date(), "HH:MM:ss")}] ${message}`); } } \ No newline at end of file diff --git a/src/helpers/MediaHelpers.ts b/src/helpers/MediaHelpers.ts index 26069a4f..33ca36c0 100644 --- a/src/helpers/MediaHelpers.ts +++ b/src/helpers/MediaHelpers.ts @@ -4,9 +4,9 @@ import { Folders } from "../commands/Folders"; import { ExtensionState, HOME_PAGE_NAVIGATION_ID, SETTINGS_CONTENT_STATIC_FOLDER } from "../constants"; import { SortingOption } from "../dashboardWebView/models"; import { MediaInfo, MediaPaths, SortOrder, SortType } from "../models"; -import { basename, extname, join, parse } from "path"; +import { basename, extname, join, parse, dirname } from "path"; import { existsSync, readdirSync, statSync, unlinkSync, writeFileSync } from "fs"; -import { commands, Uri, workspace } from "vscode"; +import { commands, Uri, workspace, window, Position } from "vscode"; import imageSize from "image-size"; import { EditorHelper } from "@estruyf/vscode"; import { ExplorerView } from "../explorerView/ExplorerView"; @@ -293,6 +293,20 @@ export class MediaHelpers { } } + /** + * Update the metadata of a media file + * @param data + */ + public static updateMetadata(data: any) { + const { file, filename, page, folder, ...metadata }: { file:string; filename:string; page: number; folder: string | null; metadata: any; } = data; + + const mediaLib = MediaLibrary.getInstance(); + mediaLib.set(file, metadata); + + // Check if filename needs to be updated + mediaLib.updateFilename(file, filename); + } + /** * Filter the media files */ diff --git a/src/helpers/MediaLibrary.ts b/src/helpers/MediaLibrary.ts index 3e550f82..7671817d 100644 --- a/src/helpers/MediaLibrary.ts +++ b/src/helpers/MediaLibrary.ts @@ -1,5 +1,4 @@ - -import { Dashboard } from '../commands/Dashboard'; +import { MediaHelpers } from './MediaHelpers'; import { workspace } from 'vscode'; import { JsonDB } from 'node-json-db/dist/JsonDB'; import { basename, dirname, join, parse } from 'path'; @@ -34,7 +33,7 @@ export class MediaLibrary { f.oldUri.path.endsWith('.png') || f.oldUri.path.endsWith('.gif')) { this.rename(f.oldUri.fsPath, f.newUri.fsPath); - Dashboard.resetMedia(); + MediaHelpers.resetMedia(); } }); }); @@ -89,7 +88,7 @@ export class MediaLibrary { } else { renameSync(filePath, newPath); this.rename(filePath, newPath); - Dashboard.resetMedia(); + MediaHelpers.resetMedia(); } } catch(err) { Notifications.error(`Something went wrong updating "${name}" to "${filename}".`); diff --git a/src/helpers/Notifications.ts b/src/helpers/Notifications.ts index db46e1b1..0f4b110f 100644 --- a/src/helpers/Notifications.ts +++ b/src/helpers/Notifications.ts @@ -1,18 +1,22 @@ import { window } from "vscode"; +import { Logger } from "."; import { EXTENSION_NAME } from "../constants"; export class Notifications { public static info(message: string, items?: any): Thenable { + Logger.info(`${EXTENSION_NAME}: ${message}`, "INFO"); return window.showInformationMessage(`${EXTENSION_NAME}: ${message}`, items); } public static warning(message: string, items?: any): Thenable { + Logger.info(`${EXTENSION_NAME}: ${message}`, "WARNING"); return window.showWarningMessage(`${EXTENSION_NAME}: ${message}`, items); } public static error(message: string, items?: any): Thenable { + Logger.info(`${EXTENSION_NAME}: ${message}`, "ERROR"); return window.showErrorMessage(`${EXTENSION_NAME}: ${message}`, items); } } \ No newline at end of file diff --git a/src/listeners/BaseListener.ts b/src/listeners/BaseListener.ts index 9e3dfbf3..006885ea 100644 --- a/src/listeners/BaseListener.ts +++ b/src/listeners/BaseListener.ts @@ -6,9 +6,7 @@ import { Logger } from "../helpers/Logger"; export abstract class BaseListener { - public static process(msg: { command: DashboardMessage, data: any }) { - Logger.info(`Receiving message from webview: ${msg.command}`); - } + public static process(msg: { command: DashboardMessage, data: any }) {} /** * Send a message to the webview diff --git a/src/listeners/DashboardListener.ts b/src/listeners/DashboardListener.ts index ffa7b722..c737fe42 100644 --- a/src/listeners/DashboardListener.ts +++ b/src/listeners/DashboardListener.ts @@ -18,7 +18,7 @@ export class DashboardListener extends BaseListener { switch(msg.command) { case DashboardMessage.getViewType: if (Dashboard.viewData) { - Dashboard.postWebviewMessage({ command: DashboardCommand.viewData, data: Dashboard.viewData }); + this.sendMsg(DashboardCommand.viewData, Dashboard.viewData); } break; case DashboardMessage.reload: diff --git a/src/listeners/ExtensionListener.ts b/src/listeners/ExtensionListener.ts index 58167918..7132c85c 100644 --- a/src/listeners/ExtensionListener.ts +++ b/src/listeners/ExtensionListener.ts @@ -2,6 +2,7 @@ import { commands, env } from "vscode"; import { SettingsListener } from "."; import { COMMAND_NAME } from "../constants"; import { DashboardMessage } from "../dashboardWebView/DashboardMessage"; +import { CustomScript, Extension } from "../helpers"; import { openFileInEditor } from "../helpers/openFileInEditor"; import { BaseListener } from "./BaseListener"; @@ -21,6 +22,19 @@ export class ExtensionListener extends BaseListener { case DashboardMessage.copyToClipboard: env.clipboard.writeText(msg.data); break; + case DashboardMessage.runCustomScript: + CustomScript.run(msg?.data?.script, msg?.data?.path); + break; + case DashboardMessage.setState: + this.setState(msg?.data); + break; + } + } + + private static setState(data: any) { + const { key, value } = data; + if (key && value) { + Extension.getInstance().setState(key, value, "workspace"); } } } \ No newline at end of file diff --git a/src/listeners/MediaListener.ts b/src/listeners/MediaListener.ts index 0b2b38a1..1640dbec 100644 --- a/src/listeners/MediaListener.ts +++ b/src/listeners/MediaListener.ts @@ -3,6 +3,8 @@ import { DashboardMessage } from "../dashboardWebView/DashboardMessage"; import { BaseListener } from "./BaseListener"; import { DashboardCommand } from '../dashboardWebView/DashboardCommand'; import { SortingOption } from '../dashboardWebView/models'; +import { commands } from 'vscode'; +import { COMMAND_NAME } from '../constants'; export class MediaListener extends BaseListener { @@ -27,7 +29,14 @@ export class MediaListener extends BaseListener { this.delete(msg?.data); break; case DashboardMessage.insertPreviewImage: - + MediaHelpers.insertMediaToMarkdown(msg?.data); + break; + case DashboardMessage.updateMediaMetadata: + this.update(msg.data); + break; + case DashboardMessage.createMediaFolder: + await commands.executeCommand(COMMAND_NAME.createFolder, msg?.data); + break; } } @@ -37,7 +46,7 @@ export class MediaListener extends BaseListener { * @param folder * @param sorting */ - private static async sendMediaFiles(page: number = 0, folder: string = '', sorting: SortingOption | null = null) { + public static async sendMediaFiles(page: number = 0, folder: string = '', sorting: SortingOption | null = null) { const files = await MediaHelpers.getMedia(page, folder, sorting); this.sendMsg(DashboardCommand.media, files); } @@ -75,4 +84,18 @@ export class MediaListener extends BaseListener { this.sendMediaFiles(data.page || 0, data.folder || ""); } catch {} } + + /** + * Update media metadata + * @param data + */ + private static update(data: any) { + try { + const { page, folder } = data; + + MediaHelpers.updateMetadata(data); + + this.sendMediaFiles(page || 0, folder || ""); + } catch {} + } } \ No newline at end of file diff --git a/src/listeners/SettingsListener.ts b/src/listeners/SettingsListener.ts index 8c7fc234..09ef84d0 100644 --- a/src/listeners/SettingsListener.ts +++ b/src/listeners/SettingsListener.ts @@ -1,13 +1,9 @@ -import { Folders } from "../commands/Folders"; -import { Template } from "../commands/Template"; -import { ExtensionState, SETTINGS_CONTENT_DRAFT_FIELD, SETTINGS_CONTENT_SORTING, SETTINGS_CONTENT_SORTING_DEFAULT, SETTINGS_CONTENT_STATIC_FOLDER, SETTINGS_DASHBOARD_MEDIA_SNIPPET, SETTINGS_DASHBOARD_OPENONSTART, SETTINGS_FRAMEWORK_ID, SETTINGS_MEDIA_SORTING_DEFAULT, SETTING_CUSTOM_SCRIPTS, SETTING_TAXONOMY_CONTENT_TYPES } from "../constants"; +import { SETTINGS_CONTENT_STATIC_FOLDER, SETTINGS_FRAMEWORK_ID } from "../constants"; import { DashboardCommand } from "../dashboardWebView/DashboardCommand"; import { DashboardMessage } from "../dashboardWebView/DashboardMessage"; -import { DashboardViewType, SortingOption } from "../dashboardWebView/models"; import { DashboardSettings, Settings } from "../helpers"; -import { Extension } from "../helpers/Extension"; import { FrameworkDetector } from "../helpers/FrameworkDetector"; -import { CustomScript, DraftField, ScriptType, SortingSetting, TaxonomyType } from "../models"; +import { Framework } from "../models"; import { BaseListener } from "./BaseListener"; @@ -27,6 +23,9 @@ export class SettingsListener extends BaseListener { case DashboardMessage.updateSetting: this.update(msg.data); break; + case DashboardMessage.setFramework: + this.setFramework(msg?.data); + break; } } @@ -49,4 +48,22 @@ export class SettingsListener extends BaseListener { this.sendMsg(DashboardCommand.settings, settings); } + + /** + * Set the current site-generator or framework + related settings + * @param frameworkId + */ + private static setFramework(frameworkId: string | null) { + Settings.update(SETTINGS_FRAMEWORK_ID, frameworkId, true); + + if (frameworkId) { + const allFrameworks = FrameworkDetector.getAll(); + const framework = allFrameworks.find((f: Framework) => f.name === frameworkId); + if (framework) { + Settings.update(SETTINGS_CONTENT_STATIC_FOLDER, framework.static, true); + } else { + Settings.update(SETTINGS_CONTENT_STATIC_FOLDER, "", true); + } + } + } } \ No newline at end of file