diff --git a/src/pages/Main/ErrorMessage.tsx b/src/pages/Main/ErrorMessage.tsx new file mode 100644 index 00000000..c03d106f --- /dev/null +++ b/src/pages/Main/ErrorMessage.tsx @@ -0,0 +1,93 @@ +import { useCallback } from 'react'; +import Button from '@material-ui/core/Button'; +import { Trans, useTranslation } from 'react-i18next'; +import styled from 'styled-components'; + +import { usePromiseValue } from '@/helpers/useServiceValue'; +import { IWorkspaceWithMetadata, IWorkspaceMetaData } from '@services/workspaces/interface'; +import { Typography } from '@material-ui/core'; + +const HelperTextsList = styled.ul` + margin-top: 0; + margin-bottom: 1.5rem; + max-width: 70vw; +`; + +interface IWikiErrorMessagesProps { + activeWorkspace: IWorkspaceWithMetadata; +} + +export function WikiErrorMessages(props: IWikiErrorMessagesProps): JSX.Element { + const { t } = useTranslation(); + const wikiLogs = usePromiseValue(async () => await window.service.wiki.getWikiLogs(props.activeWorkspace.wikiFolderLocation)); + if (wikiLogs !== undefined) { + return ( +
+ +
+
+            {wikiLogs.content}
+          
+
+
+ ); + } + return
; +} + +interface IViewLoadErrorMessagesProps { + activeWorkspaceMetadata: IWorkspaceMetaData; +} + +export function ViewLoadErrorMessages(props: IViewLoadErrorMessagesProps): JSX.Element { + const { t } = useTranslation(); + const requestReload = useCallback(async (): Promise => { + await window.service.window.reload(window.meta.windowName); + }, []); + + return ( +
+ + {t('AddWorkspace.WikiNotStarted')} + + + {props.activeWorkspaceMetadata.didFailLoadErrorMessage} + + +
+ + + <> + Try: + +
  • + Click{' '} + + Reload + {' '} + button below or press CMD_or_Ctrl + R to reload the page. +
  • +
  • + Check the{' '} + await window.service.native.open(await window.service.context.get('LOG_FOLDER'), true)} + onKeyPress={async () => await window.service.native.open(await window.service.context.get('LOG_FOLDER'), true)} + role="button" + tabIndex={0} + style={{ cursor: 'pointer' }}> + Log Folder + {' '} + to see what happened. +
  • +
  • Backup your file, remove workspace and recreate one.
  • +
    + +
    +
    + + +
    + ); +} diff --git a/src/pages/Main/NewUserMessage.tsx b/src/pages/Main/NewUserMessage.tsx new file mode 100644 index 00000000..a85c7ffd --- /dev/null +++ b/src/pages/Main/NewUserMessage.tsx @@ -0,0 +1,97 @@ +import { Trans, useTranslation } from 'react-i18next'; +import styled from 'styled-components'; + +import { WindowNames } from '@services/windows/WindowProperties'; +import { IPreferences } from '@services/preferences/interface'; + +import arrowWhite from '@/images/arrow-white.png'; +import arrowBlack from '@/images/arrow-black.png'; + +const Arrow = styled.div<{ image: string }>` + height: 202px; + width: 150px; + position: absolute; + top: 50px; + left: 72px; + + background-image: url(${({ image }) => image}); + background-size: 150px 202px; +`; + +const Avatar = styled.div` + display: inline-block; + height: 32px; + width: 32px; + /** // TODO: dark theme */ + /* background: theme.palette.type === 'dark' ? theme.palette.common.white : theme.palette.common.black; */ + border-radius: 4; + /** // TODO: dark theme */ + /* color: theme.palette.getContrastText(theme.palette.type === 'dark' ? theme.palette.common.white: theme.palette.common.black); */ + line-height: 32px; + text-align: center; + font-weight: 500; + text-transform: uppercase; + margin-left: 10px; + margin-right: 10px; + /** // TODO: dark theme */ + /* border: theme.palette.type === 'dark' ? 'none' : 1px solid rgba(0, 0, 0, 0.12); */ +`; + +const Tip2Text = styled.span` + display: inline-block; + font-size: 18px; + /** // TODO: dark theme */ + /* color: theme.palette.type === 'dark' ? theme.palette.common.white : theme.palette.common.black; */ +`; + +const TipWithSidebar = styled.div` + position: absolute; + top: 112px; + left: 180px; + user-select: none; +`; + +const TipWithoutSidebar = styled.div` + user-select: none; +`; + +const AddWorkspaceGuideInfoContainer = styled.div` + cursor: pointer; +`; + +export interface IProps { + sidebar: IPreferences['sidebar']; + themeSource: IPreferences['themeSource']; +} + +export function NewUserMessage(props: IProps): JSX.Element { + const { t } = useTranslation(); + return ( + await window.service.window.open(WindowNames.addWorkspace)}> + {props.sidebar ? ( + <> + + + + Click + + + to get started! + + + + ) : ( + + + + Click + Workspaces > Add Workspace + Or + Click Here + to get started! + + + + )} + + ); +} diff --git a/src/pages/Main/index.tsx b/src/pages/Main/index.tsx index 3debd7b7..6ff9d7cd 100644 --- a/src/pages/Main/index.tsx +++ b/src/pages/Main/index.tsx @@ -1,6 +1,6 @@ import React, { useCallback } from 'react'; import styled, { css } from 'styled-components'; -import { useTranslation, Trans } from 'react-i18next'; +import { useTranslation } from 'react-i18next'; import { Helmet } from 'react-helmet'; import { DndContext, useSensor, useSensors, PointerSensor } from '@dnd-kit/core'; import { SortableContext, arrayMove, verticalListSortingStrategy } from '@dnd-kit/sortable'; @@ -9,7 +9,7 @@ import { restrictToVerticalAxis } from '@dnd-kit/modifiers'; import SimpleBar from 'simplebar-react'; import 'simplebar/dist/simplebar.min.css'; -import { Button, Typography, Tooltip, IconButton as IconButtonRaw } from '@material-ui/core'; +import { Typography, Tooltip, IconButton as IconButtonRaw } from '@material-ui/core'; import { Settings as SettingsIcon, Upgrade as UpgradeIcon } from '@material-ui/icons'; import { WindowNames } from '@services/windows/WindowProperties'; @@ -22,14 +22,14 @@ import WorkspaceSelector from './WorkspaceSelector'; import FindInPage from '../../components/FindInPage'; import { latestUpdateUrl } from '@/constants/urls'; -import arrowWhite from '@/images/arrow-white.png'; -import arrowBlack from '@/images/arrow-black.png'; import { SortableWorkspaceSelector } from './SortableWorkspaceSelector'; import { IWorkspace } from '@services/workspaces/interface'; import { useWorkspacesListObservable } from '@services/workspaces/hooks'; import { usePreferenceObservable } from '@services/preferences/hooks'; import { CommandPaletteIcon } from '@/components/icon/CommandPaletteSVG'; import { Languages } from '../Preferences/sections/Languages'; +import { NewUserMessage } from './NewUserMessage'; +import { WikiErrorMessages, ViewLoadErrorMessages } from './ErrorMessage'; const OuterRoot = styled.div` display: flex; @@ -116,70 +116,12 @@ const ContentRoot = styled.div` width: 100%; `; -const Arrow = styled.div<{ image: string }>` - height: 202px; - width: 150px; - position: absolute; - top: 50px; - left: 72px; - - background-image: url(${({ image }) => image}); - background-size: 150px 202px; -`; - -const Avatar = styled.div` - display: inline-block; - height: 32px; - width: 32px; - /** // TODO: dark theme */ - /* background: theme.palette.type === 'dark' ? theme.palette.common.white : theme.palette.common.black; */ - border-radius: 4; - /** // TODO: dark theme */ - /* color: theme.palette.getContrastText(theme.palette.type === 'dark' ? theme.palette.common.white: theme.palette.common.black); */ - line-height: 32px; - text-align: center; - font-weight: 500; - text-transform: uppercase; - margin-left: 10px; - margin-right: 10px; - /** // TODO: dark theme */ - /* border: theme.palette.type === 'dark' ? 'none' : 1px solid rgba(0, 0, 0, 0.12); */ -`; - -const Tip2Text = styled.span` - display: inline-block; - font-size: 18px; - /** // TODO: dark theme */ - /* color: theme.palette.type === 'dark' ? theme.palette.common.white : theme.palette.common.black; */ -`; - -const TipWithSidebar = styled.div` - position: absolute; - top: 112px; - left: 180px; - user-select: none; -`; - -const TipWithoutSidebar = styled.div` - user-select: none; -`; - -const AddWorkspaceGuideInfoContainer = styled.div` - cursor: pointer; -`; - const SideBarEnd = styled.div` display: flex; flex-direction: column; align-items: center; `; -const HelperTextsList = styled.ul` - margin-top: 0; - margin-bottom: 1.5rem; - max-width: 70vw; -`; - const SidebarContainer = ({ children }: { children: React.ReactNode }): JSX.Element => { const platform = usePromiseValue(async () => await window.service.context.get('platform')); // use native scroll bar on macOS @@ -194,9 +136,6 @@ export default function Main(): JSX.Element { const workspacesList = useWorkspacesListObservable(); const preferences = usePreferenceObservable(); const isFullScreen = usePromiseValue(window.service.window.isFullScreen, false)!; - const requestReload = useCallback(async (): Promise => { - await window.service.window.reload(window.meta.windowName); - }, []); const dndSensors = useSensors( useSensor(PointerSensor, { @@ -210,6 +149,7 @@ export default function Main(): JSX.Element { const activeWorkspaceMetadata = workspacesList ?.map((workspace) => ({ active: workspace.active, ...workspace.metadata })) ?.find((workspace) => workspace.active); + const activeWorkspace = workspacesList?.find((workspace) => workspace.active); const updaterMetaData = useUpdaterObservable(); if (preferences === undefined) return
    {t('Loading')}
    ; @@ -302,86 +242,16 @@ export default function Main(): JSX.Element { + {activeWorkspace !== undefined && } {Array.isArray(workspacesList) && workspacesList.length > 0 && typeof activeWorkspaceMetadata?.didFailLoadErrorMessage === 'string' && activeWorkspaceMetadata?.didFailLoadErrorMessage.length > 0 && - activeWorkspaceMetadata?.isLoading === false && ( -
    - - {t('AddWorkspace.WikiNotStarted')} - - - {activeWorkspaceMetadata.didFailLoadErrorMessage} - - -
    - - - <> - Try: - -
  • - Click{' '} - - Reload - {' '} - button below or press CMD_or_Ctrl + R to reload the page. -
  • -
  • - Check the{' '} - await window.service.native.open(await window.service.context.get('LOG_FOLDER'), true)} - onKeyPress={async () => await window.service.native.open(await window.service.context.get('LOG_FOLDER'), true)} - role="button" - tabIndex={0} - style={{ cursor: 'pointer' }}> - Log Folder - {' '} - to see what happened. -
  • -
  • Backup your file, remove workspace and recreate one.
  • -
    - -
    -
    - - -
    - )} + activeWorkspaceMetadata?.isLoading === false && } {Array.isArray(workspacesList) && workspacesList.length > 0 && activeWorkspaceMetadata?.isLoading && ( {t('Loading')} )} - {Array.isArray(workspacesList) && workspacesList.length === 0 && ( - await window.service.window.open(WindowNames.addWorkspace)}> - {sidebar ? ( - <> - - - - Click - + - to get started! - - - - ) : ( - - - - Click - Workspaces > Add Workspace - Or - Click Here - to get started! - - - - )} - - )} + {Array.isArray(workspacesList) && workspacesList.length === 0 && }
    diff --git a/src/services/libs/log/wikiOutput.ts b/src/services/libs/log/wikiOutput.ts index b2ae2e98..6d435567 100644 --- a/src/services/libs/log/wikiOutput.ts +++ b/src/services/libs/log/wikiOutput.ts @@ -3,7 +3,7 @@ import fs from 'fs-extra'; import { LOG_FOLDER } from '@/constants/paths'; -function getWikiLogFilePath(wikiName: string): string { +export function getWikiLogFilePath(wikiName: string): string { const logFileName = wikiName.replace(/["*/:<>?\\|]/g, '_'); const logFilePath = path.join(LOG_FOLDER, `${logFileName}.log`); return logFilePath; diff --git a/src/services/view/index.ts b/src/services/view/index.ts index 2480daf0..85c0cbd4 100644 --- a/src/services/view/index.ts +++ b/src/services/view/index.ts @@ -304,6 +304,12 @@ export class View implements IViewService { workspace.name }`, ); + // will set again in view.webContents.on('did-start-loading'), but that one sometimes is too late to block services that wait for `isLoading` + await this.workspaceService.updateMetaData(workspace.id, { + // eslint-disable-next-line unicorn/no-null + didFailLoadErrorMessage: null, + isLoading: true, + }); await view.webContents.loadURL(hostReplacedUrl); logger.debug('loadInitialUrlWithCatch() await loadURL() done'); const unregisterContextMenu = await this.menuService.initContextMenuForWindowWebContents(view.webContents); diff --git a/src/services/view/setupViewEventHandlers.ts b/src/services/view/setupViewEventHandlers.ts index f0f02a41..b917643b 100644 --- a/src/services/view/setupViewEventHandlers.ts +++ b/src/services/view/setupViewEventHandlers.ts @@ -128,6 +128,7 @@ export default function setupViewEventHandlers( return; } await workspaceService.updateMetaData(workspace.id, { + isLoading: false, didFailLoadErrorMessage: `${errorCode} ${errorDesc}`, }); if (workspaceObject.active && browserWindow !== undefined && !browserWindow.isDestroyed()) { diff --git a/src/services/wiki/index.ts b/src/services/wiki/index.ts index 0164ccf6..1eff91a9 100644 --- a/src/services/wiki/index.ts +++ b/src/services/wiki/index.ts @@ -19,7 +19,7 @@ import type { IWorkspaceService, IWorkspace } from '@services/workspaces/interfa import type { IGitService, IGitUserInfos } from '@services/git/interface'; import type { IWorkspaceViewService } from '@services/workspacesView/interface'; import { WindowNames } from '@services/windows/WindowProperties'; -import { logger, wikiOutputToFile, refreshOutputFile } from '@services/libs/log'; +import { logger, wikiOutputToFile, refreshOutputFile, getWikiLogFilePath } from '@services/libs/log'; import i18n from '@services/libs/i18n'; import { lazyInject } from '@services/container'; import { TIDDLYWIKI_TEMPLATE_FOLDER_PATH, TIDDLERS_PATH } from '@/constants/paths'; @@ -636,4 +636,13 @@ export class Wiki implements IWikiService { } } } + + public async getWikiLogs(homePath: string): Promise<{ content: string; filePath: string }> { + const filePath = getWikiLogFilePath(homePath); + const content = await fs.readFile(filePath, 'utf-8'); + return { + content, + filePath, + }; + } } diff --git a/src/services/wiki/interface.ts b/src/services/wiki/interface.ts index d05e3d68..1777231c 100644 --- a/src/services/wiki/interface.ts +++ b/src/services/wiki/interface.ts @@ -51,6 +51,7 @@ export interface IWikiService { createSubWiki(parentFolderLocation: string, folderName: string, mainWikiPath: string, tagName?: string, onlyLink?: boolean): Promise; ensureWikiExist(wikiPath: string, shouldBeMainWiki: boolean): Promise; getSubWikiPluginContent(mainWikiPath: string): Promise; + getWikiLogs(homePath: string): Promise<{ content: string; filePath: string }>; linkWiki(mainWikiPath: string, folderName: string, subWikiPath: string): Promise; /** * Open image or PDF in OS native viewer or some else usage like this. @@ -91,6 +92,7 @@ export const WikiServiceIPCDescriptor = { createSubWiki: ProxyPropertyType.Function, ensureWikiExist: ProxyPropertyType.Function, getSubWikiPluginContent: ProxyPropertyType.Function, + getWikiLogs: ProxyPropertyType.Function, linkWiki: ProxyPropertyType.Function, openTiddlerInExternal: ProxyPropertyType.Function, removeWiki: ProxyPropertyType.Function, diff --git a/src/services/wiki/wikiWorker.ts b/src/services/wiki/wikiWorker.ts index 2b6e4de9..ebc07cfc 100644 --- a/src/services/wiki/wikiWorker.ts +++ b/src/services/wiki/wikiWorker.ts @@ -5,7 +5,6 @@ import tiddlywiki, { I$TW } from '@tiddlygit/tiddlywiki'; import { Observable } from 'rxjs'; import intercept from 'intercept-stdout'; import { Server } from 'http'; -import { shell } from 'electron'; import { IWikiMessage, WikiControlActions } from './interface'; import { defaultServerIP } from '@/constants/urls';