mirror of
https://github.com/tiddly-gittly/TidGi-Desktop.git
synced 2025-12-06 02:30:47 -08:00
parent
91fd128a68
commit
04879c741c
13 changed files with 114 additions and 31 deletions
|
|
@ -2,6 +2,7 @@
|
|||
"Hello": "Hello",
|
||||
"WorkspaceSelector": {
|
||||
"Add": "Add",
|
||||
"Guide": "Guide",
|
||||
"OpenWorkspaceTagTiddler": "Open {{tagName}}",
|
||||
"DefaultTiddlers": "Default Tiddlers",
|
||||
"OpenWorkspaceMenuName": "Open Workspace",
|
||||
|
|
@ -229,7 +230,8 @@
|
|||
"CheckingRebaseStatus": "Analyzing the rebase processing plan",
|
||||
"InitializeWikiGit": "Initializing Wiki and Git",
|
||||
"InitializeWorkspaceView": "Initializing workspace and browser view, and loading the web content, please wait",
|
||||
"GitTokenExpireOrWrong": "The Git credential (Token) has expired and you need to log in again, or the credential does not correspond to the user name"
|
||||
"GitTokenExpireOrWrong": "The Git credential (Token) has expired and you need to log in again, or the credential does not correspond to the user name",
|
||||
"InitializeWorkspaceViewDone": "Created successfully, content will be loaded soon"
|
||||
},
|
||||
"Cancel": "Cancel",
|
||||
"Preference": {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
"LinOnetwo": "林一二",
|
||||
"WorkspaceSelector": {
|
||||
"Add": "添加",
|
||||
"Guide": "引导",
|
||||
"OpenWorkspaceTagTiddler": "打开 {{tagName}}",
|
||||
"DefaultTiddlers": "默认条目",
|
||||
"OpenWorkspaceMenuName": "打开工作区",
|
||||
|
|
@ -247,6 +248,7 @@
|
|||
"SynchronizationFinish": "同步完成",
|
||||
"InitializeWikiGit": "正在初始化 Wiki 和 Git",
|
||||
"InitializeWorkspaceView": "正在初始化工作区和浏览器窗口,并加载内容,请耐心等待",
|
||||
"InitializeWorkspaceViewDone": "创建成功,即将加载内容",
|
||||
"PrepareCloneOnlineWiki": "准备导入线上 Wiki",
|
||||
"StartFetchingFromGithubRemote": "正在拉取Github远端仓库的数据,需要的时间取决于网速和仓库大小,请耐心等待",
|
||||
"UsingUrlAndUsername": "使用 Git Url {{githubRepoUrl}} 和用户名 {{username}} 和 accessToken {{accessToken}}"
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ const AvatarPicture = styled.img<{ large?: boolean }>`
|
|||
`}
|
||||
`;
|
||||
|
||||
const ShortcutText = styled.p`
|
||||
const ShortcutText = styled.p<{ active?: boolean }>`
|
||||
margin-top: 2px;
|
||||
margin-bottom: 0;
|
||||
padding: 0;
|
||||
|
|
@ -118,6 +118,12 @@ const ShortcutText = styled.p`
|
|||
display: inline-block;
|
||||
word-break: break-all;
|
||||
text-align: center;
|
||||
${({ active }) =>
|
||||
active === true &&
|
||||
css`
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 0.2em;
|
||||
`}
|
||||
`;
|
||||
const Badge = styled(BadgeRaw)`
|
||||
line-height: 20px;
|
||||
|
|
@ -171,15 +177,21 @@ export function WorkspaceSelector({
|
|||
transparent={transparentBackground}
|
||||
addAvatar={id === 'add'}
|
||||
highlightAdd={index === 0}
|
||||
id={id === 'add' ? 'add-workspace-button' : `workspace-avatar-${id}`}>
|
||||
id={id === 'add' || id === 'guide' ? 'add-workspace-button' : `workspace-avatar-${id}`}>
|
||||
{id === 'add' ? (
|
||||
'+'
|
||||
) : id === 'guide' ? (
|
||||
'※'
|
||||
) : (
|
||||
<AvatarPicture alt="Icon" large={!showSidebarShortcutHints} src={getAssetsFileUrl(picturePath ?? defaultIcon)} draggable={false} />
|
||||
)}
|
||||
</Avatar>
|
||||
</Badge>
|
||||
{showSidebarShortcutHints && <ShortcutText>{id === 'add' ? t('WorkspaceSelector.Add') : shortWorkspaceName}</ShortcutText>}
|
||||
{showSidebarShortcutHints && (
|
||||
<ShortcutText active={active}>
|
||||
{id === 'add' ? t('WorkspaceSelector.Add') : id === 'guide' ? t('WorkspaceSelector.Guide') : shortWorkspaceName}
|
||||
</ShortcutText>
|
||||
)}
|
||||
</Root>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,3 +31,5 @@ export const LOCALIZATION_FOLDER = isDevelopmentOrTest
|
|||
? path.resolve(sourcePath, '..', localizationFolderName)
|
||||
: path.resolve(process.resourcesPath, localizationFolderName);
|
||||
export const DEFAULT_WIKI_FOLDER = isDevelopmentOrTest ? path.resolve(os.tmpdir(), developmentWikiFolderName) : DESKTOP_PATH;
|
||||
export const DEFAULT_FIRST_WIKI_NAME = 'wiki';
|
||||
export const DEFAULT_FIRST_WIKI_PATH = path.join(DEFAULT_WIKI_FOLDER, DEFAULT_FIRST_WIKI_NAME);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ export async function callWikiInitialization(
|
|||
wikiCreationMessageSetter: (m: string) => void,
|
||||
t: TFunction<'translation'>,
|
||||
gitUserInfo: IGitUserInfos | undefined,
|
||||
notClose?: boolean,
|
||||
): Promise<void> {
|
||||
wikiCreationMessageSetter(t('Log.InitializeWikiGit'));
|
||||
const newWorkspace = await window.service.wikiGitWorkspace.initWikiGitTransaction(newWorkspaceConfig, gitUserInfo);
|
||||
|
|
@ -17,7 +18,11 @@ export async function callWikiInitialization(
|
|||
wikiCreationMessageSetter(t('Log.InitializeWorkspaceView'));
|
||||
/** create workspace from workspaceService to store workspace configs, and create a BrowserView to actually display wiki web content from viewService */
|
||||
await window.service.workspaceView.initializeWorkspaceView(newWorkspace, { isNew: true });
|
||||
wikiCreationMessageSetter(t('Log.InitializeWorkspaceViewDone'));
|
||||
await window.service.workspaceView.setActiveWorkspaceView(newWorkspace.id);
|
||||
// wait for wiki to start and close the window now.
|
||||
await window.remote.closeCurrentWindow();
|
||||
wikiCreationMessageSetter('');
|
||||
if (notClose !== true) {
|
||||
// wait for wiki to start and close the window now.
|
||||
await window.remote.closeCurrentWindow();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable @typescript-eslint/ban-types */
|
||||
/* eslint-disable unicorn/no-null */
|
||||
/* eslint-disable @typescript-eslint/strict-boolean-expressions */
|
||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
||||
|
|
@ -10,6 +11,7 @@ import { useStorageServiceUserInfoObservable } from '@services/auth/hooks';
|
|||
import { SupportedStorageServices } from '@services/types';
|
||||
import { ISubWikiPluginContent } from '@services/wiki/plugin/subWikiPlugin';
|
||||
import { INewWorkspaceConfig, IWorkspace } from '@services/workspaces/interface';
|
||||
import type { INewWikiRequiredFormData } from './useNewWiki';
|
||||
|
||||
export function useIsCreateSyncedWorkspace(): [boolean, React.Dispatch<React.SetStateAction<boolean>>] {
|
||||
const [isCreateSyncedWorkspace, isCreateSyncedWorkspaceSetter] = useState(false);
|
||||
|
|
@ -151,15 +153,15 @@ export interface IWikiWorkspaceFormProps {
|
|||
isCreateMainWorkspace: boolean;
|
||||
}
|
||||
|
||||
export function workspaceConfigFromForm(form: IWikiWorkspaceForm, isCreateMainWorkspace: boolean, isCreateSyncedWorkspace: boolean): INewWorkspaceConfig {
|
||||
export function workspaceConfigFromForm(form: INewWikiRequiredFormData, isCreateMainWorkspace: boolean, isCreateSyncedWorkspace: boolean): INewWorkspaceConfig {
|
||||
return {
|
||||
gitUrl: isCreateSyncedWorkspace ? form.gitRepoUrl : null,
|
||||
isSubWiki: !isCreateMainWorkspace,
|
||||
mainWikiToLink: !isCreateMainWorkspace ? form.mainWikiToLink.wikiFolderLocation : null,
|
||||
mainWikiID: !isCreateMainWorkspace ? form.mainWikiToLink.id : null,
|
||||
mainWikiToLink: isCreateMainWorkspace ? null : form.mainWikiToLink.wikiFolderLocation,
|
||||
mainWikiID: isCreateMainWorkspace ? null : form.mainWikiToLink.id,
|
||||
name: form.wikiFolderName,
|
||||
storageService: form.storageProvider,
|
||||
tagName: !isCreateMainWorkspace ? form.tagName : null,
|
||||
tagName: isCreateMainWorkspace ? null : form.tagName,
|
||||
port: form.wikiPort,
|
||||
wikiFolderLocation: form.wikiFolderLocation!,
|
||||
backupOnInterval: true,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
/* eslint-disable @typescript-eslint/ban-types */
|
||||
/* eslint-disable @typescript-eslint/strict-boolean-expressions */
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { callWikiInitialization } from './useCallWikiInitialization';
|
||||
import { IErrorInWhichComponent, IWikiWorkspaceForm, workspaceConfigFromForm } from './useForm';
|
||||
import { updateErrorInWhichComponentSetterByErrorMessage } from './useIndicator';
|
||||
import { ConditionalExcept } from 'type-fest';
|
||||
|
||||
export function useValidateNewWiki(
|
||||
isCreateMainWorkspace: boolean,
|
||||
|
|
@ -56,20 +58,21 @@ export function useValidateNewWiki(
|
|||
return [hasError, wikiCreationMessage, wikiCreationMessageSetter, hasErrorSetter];
|
||||
}
|
||||
|
||||
export type INewWikiRequiredFormData = ConditionalExcept<IWikiWorkspaceForm, Function>;
|
||||
export function useNewWiki(
|
||||
isCreateMainWorkspace: boolean,
|
||||
isCreateSyncedWorkspace: boolean,
|
||||
form: IWikiWorkspaceForm,
|
||||
form: INewWikiRequiredFormData,
|
||||
wikiCreationMessageSetter: (m: string) => void,
|
||||
hasErrorSetter: (m: boolean) => void,
|
||||
errorInWhichComponentSetter: (errors: IErrorInWhichComponent) => void,
|
||||
options?: { noCopyTemplate?: boolean },
|
||||
hasErrorSetter?: (m: boolean) => void,
|
||||
errorInWhichComponentSetter?: (errors: IErrorInWhichComponent) => void,
|
||||
options?: { noCopyTemplate?: boolean; notClose?: boolean },
|
||||
): () => Promise<void> {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const onSubmit = useCallback(async () => {
|
||||
wikiCreationMessageSetter(t('AddWorkspace.Processing'));
|
||||
hasErrorSetter(false);
|
||||
hasErrorSetter?.(false);
|
||||
try {
|
||||
const newWorkspaceConfig = workspaceConfigFromForm(form, isCreateMainWorkspace, isCreateSyncedWorkspace);
|
||||
if (isCreateMainWorkspace) {
|
||||
|
|
@ -79,22 +82,13 @@ export function useNewWiki(
|
|||
} else {
|
||||
await window.service.wiki.createSubWiki(form.parentFolderLocation, form.wikiFolderName, form.mainWikiToLink?.wikiFolderLocation, form.tagName);
|
||||
}
|
||||
await callWikiInitialization(newWorkspaceConfig, wikiCreationMessageSetter, t, form.gitUserInfo);
|
||||
await callWikiInitialization(newWorkspaceConfig, wikiCreationMessageSetter, t, form.gitUserInfo, options?.notClose);
|
||||
} catch (error) {
|
||||
wikiCreationMessageSetter((error as Error).message);
|
||||
updateErrorInWhichComponentSetterByErrorMessage(t, (error as Error).message, errorInWhichComponentSetter);
|
||||
hasErrorSetter(true);
|
||||
errorInWhichComponentSetter && updateErrorInWhichComponentSetterByErrorMessage(t, (error as Error).message, errorInWhichComponentSetter);
|
||||
hasErrorSetter?.(true);
|
||||
}
|
||||
}, [
|
||||
wikiCreationMessageSetter,
|
||||
t,
|
||||
hasErrorSetter,
|
||||
form,
|
||||
isCreateMainWorkspace,
|
||||
isCreateSyncedWorkspace,
|
||||
options?.noCopyTemplate,
|
||||
errorInWhichComponentSetter,
|
||||
]);
|
||||
}, [wikiCreationMessageSetter, t, hasErrorSetter, form, isCreateMainWorkspace, isCreateSyncedWorkspace, options, errorInWhichComponentSetter]);
|
||||
|
||||
return onSubmit;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
/* eslint-disable @typescript-eslint/strict-boolean-expressions */
|
||||
/* eslint-disable @typescript-eslint/promise-function-async */
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import styled, { css } from 'styled-components';
|
||||
import is, { isNot } from 'typescript-styled-is';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
|
@ -28,6 +29,7 @@ import { Languages } from '../Preferences/sections/Languages';
|
|||
import { TiddlyWiki } from '../Preferences/sections/TiddlyWiki';
|
||||
import { NewUserMessage } from './NewUserMessage';
|
||||
import { WikiErrorMessages, ViewLoadErrorMessages } from './ErrorMessage';
|
||||
import { useAutoCreateFirstWorkspace } from './useAutoCreateFirstWorkspace';
|
||||
|
||||
const OuterRoot = styled.div`
|
||||
display: flex;
|
||||
|
|
@ -151,6 +153,8 @@ const SidebarContainer = ({ children }: { children: React.ReactNode }): JSX.Elem
|
|||
export default function Main(): JSX.Element {
|
||||
const { t } = useTranslation();
|
||||
const workspacesList = useWorkspacesListObservable();
|
||||
const [wikiCreationMessage, wikiCreationMessageSetter] = useState('');
|
||||
useAutoCreateFirstWorkspace(workspacesList, wikiCreationMessageSetter);
|
||||
const preferences = usePreferenceObservable();
|
||||
/** is title bar on. This only take effect after reload, so we don't want to get this preference from observable */
|
||||
const titleBar = usePromiseValue<boolean>(() => window.service.preference.get('titleBar'), false)!;
|
||||
|
|
@ -188,6 +192,13 @@ export default function Main(): JSX.Element {
|
|||
showSidebarShortcutHints={sidebarShortcutHints}
|
||||
onClick={() => void window.service.window.open(WindowNames.addWorkspace)}
|
||||
/>
|
||||
<WorkspaceSelector
|
||||
id="guide"
|
||||
index={workspacesList?.length ? workspacesList.length + 1 : 1}
|
||||
active={activeWorkspace?.id === undefined}
|
||||
showSidebarShortcutHints={sidebarShortcutHints}
|
||||
onClick={() => void window.service.workspace.clearActiveWorkspace(activeWorkspace?.id)}
|
||||
/>
|
||||
</SidebarTop>
|
||||
<SideBarEnd>
|
||||
{(workspacesList?.length ?? 0) > 0 && (
|
||||
|
|
@ -233,6 +244,7 @@ export default function Main(): JSX.Element {
|
|||
{Array.isArray(workspacesList) && workspacesList.length > 0 && activeWorkspaceMetadata?.isLoading === true && (
|
||||
<Typography color="textSecondary">{t('Loading')}</Typography>
|
||||
)}
|
||||
{wikiCreationMessage && <Typography color="textSecondary">{wikiCreationMessage}</Typography>}
|
||||
{Array.isArray(workspacesList) && workspacesList.length === 0 && <NewUserMessage sidebar={sidebar} themeSource={themeSource} />}
|
||||
</InnerContentRoot>
|
||||
<Languages languageSelectorOnly />
|
||||
|
|
|
|||
40
src/pages/Main/useAutoCreateFirstWorkspace.ts
Normal file
40
src/pages/Main/useAutoCreateFirstWorkspace.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/* eslint-disable @typescript-eslint/promise-function-async */
|
||||
import { useEffect, useState } from 'react';
|
||||
import { IWorkspaceWithMetadata } from '@services/workspaces/interface';
|
||||
import { INewWikiRequiredFormData, useNewWiki } from '../AddWorkspace/useNewWiki';
|
||||
import { SupportedStorageServices } from '@services/types';
|
||||
import { useWikiWorkspaceForm } from '../AddWorkspace/useForm';
|
||||
import { usePromiseValue } from '@/helpers/useServiceValue';
|
||||
|
||||
export function useAutoCreateFirstWorkspace(workspacesList: IWorkspaceWithMetadata[] | undefined, wikiCreationMessageSetter: (m: string) => void): void {
|
||||
const form = useWikiWorkspaceForm();
|
||||
const DEFAULT_FIRST_WIKI_PATH = usePromiseValue<string | undefined>(() => window.service.context.get('DEFAULT_FIRST_WIKI_PATH'));
|
||||
const DEFAULT_WIKI_FOLDER = usePromiseValue<string | undefined>(() => window.service.context.get('DEFAULT_WIKI_FOLDER'))!;
|
||||
const defaultNewWorkspaceConfig: INewWikiRequiredFormData = {
|
||||
...form,
|
||||
wikiFolderName: 'wiki',
|
||||
wikiFolderLocation: DEFAULT_FIRST_WIKI_PATH,
|
||||
parentFolderLocation: DEFAULT_WIKI_FOLDER,
|
||||
storageProvider: SupportedStorageServices.local,
|
||||
wikiPort: 5212,
|
||||
};
|
||||
|
||||
/** allow user delete all workspace, to enter the empty list state. */
|
||||
const [created, createdSetter] = useState(false);
|
||||
const onSubmit = useNewWiki(true, false, defaultNewWorkspaceConfig, wikiCreationMessageSetter, undefined, undefined, { notClose: true });
|
||||
|
||||
useEffect(() => {
|
||||
if (created) return;
|
||||
// skip this logic if already have workspaces
|
||||
if (workspacesList?.length !== undefined && workspacesList?.length > 0) {
|
||||
createdSetter(true);
|
||||
return;
|
||||
}
|
||||
// if is first opened (or page refreshed) with empty workspace list, create one
|
||||
if (DEFAULT_WIKI_FOLDER === undefined || DEFAULT_FIRST_WIKI_PATH === undefined) return;
|
||||
if (workspacesList?.length === 0) {
|
||||
createdSetter(true);
|
||||
void onSubmit();
|
||||
}
|
||||
}, [workspacesList?.length, created, createdSetter, onSubmit, DEFAULT_WIKI_FOLDER, DEFAULT_FIRST_WIKI_PATH]);
|
||||
}
|
||||
|
|
@ -3,6 +3,8 @@ import { ContextChannel } from '@/constants/channels';
|
|||
|
||||
export interface IPaths {
|
||||
CHROME_ERROR_PATH: string;
|
||||
DEFAULT_FIRST_WIKI_NAME: string;
|
||||
DEFAULT_FIRST_WIKI_PATH: string;
|
||||
DEFAULT_WIKI_FOLDER: string;
|
||||
DESKTOP_PATH: string;
|
||||
LOCALIZATION_FOLDER: string;
|
||||
|
|
|
|||
|
|
@ -355,7 +355,14 @@ export class Workspace implements IWorkspaceService {
|
|||
// active new one
|
||||
await this.update(id, { active: true, hibernated: false });
|
||||
// de-active the other one
|
||||
if (typeof oldActiveWorkspaceID === 'string' && oldActiveWorkspaceID !== id) {
|
||||
if (oldActiveWorkspaceID !== id) {
|
||||
await this.clearActiveWorkspace(oldActiveWorkspaceID);
|
||||
}
|
||||
}
|
||||
|
||||
public async clearActiveWorkspace(oldActiveWorkspaceID: string | undefined): Promise<void> {
|
||||
// de-active the other one
|
||||
if (typeof oldActiveWorkspaceID === 'string') {
|
||||
await this.update(oldActiveWorkspaceID, { active: false });
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,6 +121,8 @@ export type INewWorkspaceConfig = SetOptional<
|
|||
* Manage workspace level preferences and workspace metadata.
|
||||
*/
|
||||
export interface IWorkspaceService {
|
||||
/** Enter a state that no workspace is active (show welcome page) */
|
||||
clearActiveWorkspace(oldActiveWorkspaceID: string | undefined): Promise<void>;
|
||||
countWorkspaces(): Promise<number>;
|
||||
create(newWorkspaceConfig: INewWorkspaceConfig): Promise<IWorkspace>;
|
||||
get(id: string): Promise<IWorkspace | undefined>;
|
||||
|
|
@ -157,6 +159,7 @@ export const WorkspaceServiceIPCDescriptor = {
|
|||
channel: WorkspaceChannel.name,
|
||||
properties: {
|
||||
countWorkspaces: ProxyPropertyType.Function,
|
||||
clearActiveWorkspace: ProxyPropertyType.Function,
|
||||
create: ProxyPropertyType.Function,
|
||||
get: ProxyPropertyType.Function,
|
||||
get$: ProxyPropertyType.Function$,
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit ad3d8c893017855fbbf70c31e1cdb9f17e3b3dbc
|
||||
Subproject commit 8a465b27541f310ae59d84774df7cdaa47c5eff1
|
||||
Loading…
Add table
Add a link
Reference in a new issue