mirror of
https://github.com/tiddly-gittly/TidGi-Desktop.git
synced 2025-12-06 02:30:47 -08:00
refactor: move AddWorkspace form into hooks
This commit is contained in:
parent
52fa8943e4
commit
67a70f2829
16 changed files with 264 additions and 228 deletions
40
src/components/TokenForm/index.tsx
Normal file
40
src/components/TokenForm/index.tsx
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { Paper, Typography } from '@material-ui/core';
|
||||
import SearchRepo from '@/components/github/SearchRepo';
|
||||
|
||||
import { GithubTokenForm } from '../github/git-token-form';
|
||||
|
||||
const SyncContainer = styled(Paper)`
|
||||
margin-top: 5px;
|
||||
`;
|
||||
const GithubRepoLink = styled(Typography)`
|
||||
cursor: pointer;
|
||||
opacity: 50%;
|
||||
&:hover {
|
||||
opacity: 100%;
|
||||
}
|
||||
`;
|
||||
|
||||
export function TokenForm(): JSX.Element {
|
||||
return (
|
||||
<SyncContainer elevation={2} square>
|
||||
<GithubTokenForm>
|
||||
{githubWikiUrl?.length > 0 ? (
|
||||
<GithubRepoLink onClick={async () => await window.service.native.open(githubWikiUrl)} variant="subtitle2" align="center">
|
||||
({githubWikiUrl})
|
||||
</GithubRepoLink>
|
||||
) : undefined}
|
||||
<SearchRepo
|
||||
githubWikiUrl={githubWikiUrl}
|
||||
accessToken={accessToken}
|
||||
githubWikiUrlSetter={githubWikiUrlSetter}
|
||||
userInfo={userInfo}
|
||||
currentTab={currentTab}
|
||||
wikiFolderNameSetter={wikiFolderNameSetter}
|
||||
isCreateMainWorkspace={isCreateMainWorkspace}
|
||||
/>
|
||||
</GithubTokenForm>
|
||||
</SyncContainer>
|
||||
)
|
||||
}
|
||||
|
|
@ -16,6 +16,18 @@ export const getGithubToken = async (): Promise<string | undefined> => await win
|
|||
export function GithubTokenForm(props: { children?: JSX.Element | Array<JSX.Element | undefined | string> }): JSX.Element {
|
||||
const { children } = props;
|
||||
const { t } = useTranslation();
|
||||
useEffect(() => {
|
||||
// on startup, loading the cachedGithubToken
|
||||
if (accessToken === undefined && cachedGithubToken !== undefined) {
|
||||
graphqlClient.setHeader('Authorization', `bearer ${cachedGithubToken}`);
|
||||
accessTokenSetter(cachedGithubToken);
|
||||
} else if (accessToken !== undefined && accessToken !== cachedGithubToken) {
|
||||
// if user or login button changed the token, we use latest token
|
||||
Object.keys(graphqlClient.headers).map((key) => graphqlClient.removeHeader(key));
|
||||
accessTokenSetter(accessToken);
|
||||
void setGithubToken(accessToken);
|
||||
}
|
||||
}, [cachedGithubToken, accessToken]);
|
||||
const userInfo = useUserInfoObservable();
|
||||
if (userInfo === undefined) {
|
||||
return <div>Loading...</div>;
|
||||
|
|
|
|||
49
src/pages/AddWorkspace/TabBar.tsx
Normal file
49
src/pages/AddWorkspace/TabBar.tsx
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
import React from 'react';
|
||||
import { invert } from 'lodash';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { Paper, AppBar, Tabs, Tab } from '@material-ui/core';
|
||||
|
||||
export enum CreateWorkspaceTabs {
|
||||
CloneOnlineWiki = 'CloneOnlineWiki',
|
||||
CreateNewWiki = 'CreateNewWiki',
|
||||
OpenLocalWiki = 'OpenLocalWiki',
|
||||
}
|
||||
|
||||
const a11yProps = (
|
||||
index: CreateWorkspaceTabs,
|
||||
): {
|
||||
id: string;
|
||||
'aria-controls': string;
|
||||
} => ({
|
||||
id: index,
|
||||
'aria-controls': `simple-tabpanel-${index}`,
|
||||
});
|
||||
|
||||
const tabIndexMap = {
|
||||
[CreateWorkspaceTabs.CloneOnlineWiki]: 0,
|
||||
[CreateWorkspaceTabs.CreateNewWiki]: 1,
|
||||
[CreateWorkspaceTabs.OpenLocalWiki]: 2,
|
||||
};
|
||||
|
||||
export interface IProps {
|
||||
currentTab: CreateWorkspaceTabs;
|
||||
currentTabSetter: (id: CreateWorkspaceTabs) => void;
|
||||
}
|
||||
export function TabBar({ currentTab, currentTabSetter }: IProps): JSX.Element {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<AppBar position="static">
|
||||
<Paper square>
|
||||
<Tabs
|
||||
value={tabIndexMap[currentTab]}
|
||||
onChange={(_event, newValue: number) => currentTabSetter((invert(tabIndexMap) as Record<number, CreateWorkspaceTabs>)[newValue])}
|
||||
aria-label={t('AddWorkspace.SwitchCreateNewOrOpenExisted')}>
|
||||
<Tab label={t(`AddWorkspace.CloneOnlineWiki`)} {...a11yProps(CreateWorkspaceTabs.CloneOnlineWiki)} />
|
||||
<Tab label={t('AddWorkspace.CreateNewWiki')} {...a11yProps(CreateWorkspaceTabs.CreateNewWiki)} />
|
||||
<Tab label={t('AddWorkspace.OpenLocalWiki')} {...a11yProps(CreateWorkspaceTabs.OpenLocalWiki)} />
|
||||
</Tabs>
|
||||
</Paper>
|
||||
</AppBar>
|
||||
);
|
||||
}
|
||||
|
|
@ -39,7 +39,7 @@ interface StateProps {
|
|||
|
||||
type Props = OwnProps & DispatchProps & StateProps;
|
||||
|
||||
function CloneWikiDoneButton({
|
||||
export function CloneWikiDoneButton({
|
||||
isCreateMainWorkspace,
|
||||
wikiPort,
|
||||
mainWikiToLink,
|
||||
|
|
|
|||
|
|
@ -2,23 +2,18 @@ import React, { useState, useEffect } from 'react';
|
|||
import styled from 'styled-components';
|
||||
import { GraphQLClient, ClientContext } from 'graphql-hooks';
|
||||
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import Paper from '@material-ui/core/Paper';
|
||||
|
||||
import { GITHUB_GRAPHQL_API } from '../../constants/auth';
|
||||
|
||||
import Description from './description-and-mode-switch';
|
||||
import SearchRepo from './search-repo';
|
||||
|
||||
import NewWikiDoneButton from './new-wiki-done-button';
|
||||
import NewWikiPathForm from './new-wiki-path-form';
|
||||
import ExistedWikiPathForm from './existed-wiki-path-form';
|
||||
import ExistedWikiDoneButton from './existed-wiki-done-button';
|
||||
import CloneWikiDoneButton from './clone-wiki-done-button';
|
||||
import type { ISubWikiPluginContent } from '@services/wiki/update-plugin-content';
|
||||
import type { IAuthingUserInfo } from '@services/types';
|
||||
import TabBar from './tab-bar';
|
||||
import { GithubTokenForm, getGithubToken, setGithubToken } from '../../components/github/git-token-form';
|
||||
import { usePromiseValue, usePromiseValueAndSetter } from '@/helpers/useServiceValue';
|
||||
|
||||
import { TabBar, CreateWorkspaceTabs } from './TabBar';
|
||||
import { useIsCreateMainWorkspace, useWikiWorkspaceForm } from './useForm';
|
||||
|
||||
const graphqlClient = new GraphQLClient({
|
||||
url: GITHUB_GRAPHQL_API,
|
||||
|
|
@ -32,183 +27,36 @@ const Container = styled.main`
|
|||
width: 0;
|
||||
}
|
||||
`;
|
||||
const SyncContainer = styled(Paper)`
|
||||
margin-top: 5px;
|
||||
`;
|
||||
const GithubRepoLink = styled(Typography)`
|
||||
cursor: pointer;
|
||||
opacity: 50%;
|
||||
&:hover {
|
||||
opacity: 100%;
|
||||
}
|
||||
`;
|
||||
|
||||
export default function AddWorkspace(): JSX.Element {
|
||||
const [currentTab, currentTabSetter] = useState('CloneOnlineWiki');
|
||||
const [isCreateMainWorkspace, isCreateMainWorkspaceSetter] = useState(false);
|
||||
useEffect(() => {
|
||||
void window.service.workspace.countWorkspaces().then((workspaceCount) => isCreateMainWorkspaceSetter(workspaceCount === 0));
|
||||
}, []);
|
||||
const parentFolderLocation = usePromiseValue(async () => (await window.service.context.get('DESKTOP_PATH')) as string);
|
||||
const existedFolderLocation = usePromiseValue(async () => (await window.service.context.get('DESKTOP_PATH')) as string);
|
||||
const [currentTab, currentTabSetter] = useState<CreateWorkspaceTabs>(CreateWorkspaceTabs.CreateNewWiki);
|
||||
const [isCreateMainWorkspace, isCreateMainWorkspaceSetter] = useIsCreateMainWorkspace();
|
||||
|
||||
const [wikiPort, wikiPortSetter] = useState(5212);
|
||||
useEffect(() => {
|
||||
// only update default port on component mount
|
||||
void window.service.workspace.countWorkspaces().then((workspaceCount) => wikiPortSetter(wikiPort + workspaceCount));
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
// TODO: refactor GITHUB related things out, make it can switch between vendors
|
||||
const cachedGithubToken = usePromiseValue(getGithubToken);
|
||||
// try get token on start up, so Github GraphQL client can use it
|
||||
const [accessToken, accessTokenSetter] = useState<string | undefined>();
|
||||
// try get token from local storage, and set to state for gql to use
|
||||
useEffect(() => {
|
||||
// on startup, loading the cachedGithubToken
|
||||
if (accessToken === undefined && cachedGithubToken !== undefined) {
|
||||
graphqlClient.setHeader('Authorization', `bearer ${cachedGithubToken}`);
|
||||
accessTokenSetter(cachedGithubToken);
|
||||
} else if (accessToken !== undefined && accessToken !== cachedGithubToken) {
|
||||
// if user or login button changed the token, we use latest token
|
||||
Object.keys(graphqlClient.headers).map((key) => graphqlClient.removeHeader(key));
|
||||
accessTokenSetter(accessToken);
|
||||
void setGithubToken(accessToken);
|
||||
}
|
||||
}, [cachedGithubToken, accessToken]);
|
||||
|
||||
const [userName, userNameSetter] = usePromiseValueAndSetter(
|
||||
async () => await window.service.auth.get('userName'),
|
||||
async (newUserName) => await window.service.auth.set('userName', newUserName),
|
||||
);
|
||||
|
||||
const [mainWikiToLink, mainWikiToLinkSetter] = useState({ name: '', port: 0 });
|
||||
const [tagName, tagNameSetter] = useState<string>('');
|
||||
const [fileSystemPaths, fileSystemPathsSetter] = useState<ISubWikiPluginContent[]>([]);
|
||||
useEffect(() => {
|
||||
void window.service.wiki.getSubWikiPluginContent(mainWikiToLink.name).then(fileSystemPathsSetter);
|
||||
}, [mainWikiToLink]);
|
||||
const [githubWikiUrl, githubWikiUrlSetter] = useState<string>('');
|
||||
useEffect(() => {
|
||||
void (async function getWorkspaceRemoteInEffect(): Promise<void> {
|
||||
if (existedFolderLocation !== undefined) {
|
||||
const url = await window.service.git.getWorkspacesRemote(existedFolderLocation);
|
||||
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
||||
if (url) {
|
||||
githubWikiUrlSetter(url);
|
||||
}
|
||||
}
|
||||
})();
|
||||
}, [githubWikiUrl, existedFolderLocation]);
|
||||
|
||||
const [wikiFolderName, wikiFolderNameSetter] = useState('tiddlywiki');
|
||||
const form = useWikiWorkspaceForm();
|
||||
|
||||
return (
|
||||
<ClientContext.Provider value={graphqlClient}>
|
||||
<TabBar currentTab={currentTab} currentTabSetter={currentTabSetter} />
|
||||
<Description isCreateMainWorkspace={isCreateMainWorkspace} isCreateMainWorkspaceSetter={isCreateMainWorkspaceSetter} />
|
||||
<SyncContainer elevation={2} square>
|
||||
<GithubTokenForm>
|
||||
{githubWikiUrl?.length > 0 ? (
|
||||
<GithubRepoLink onClick={async () => await window.service.native.open(githubWikiUrl)} variant="subtitle2" align="center">
|
||||
({githubWikiUrl})
|
||||
</GithubRepoLink>
|
||||
) : undefined}
|
||||
<SearchRepo
|
||||
githubWikiUrl={githubWikiUrl}
|
||||
accessToken={accessToken}
|
||||
githubWikiUrlSetter={githubWikiUrlSetter}
|
||||
userInfo={userInfo}
|
||||
currentTab={currentTab}
|
||||
wikiFolderNameSetter={wikiFolderNameSetter}
|
||||
isCreateMainWorkspace={isCreateMainWorkspace}
|
||||
/>
|
||||
</GithubTokenForm>
|
||||
</SyncContainer>
|
||||
|
||||
{currentTab === 'CreateNewWiki' && (
|
||||
<Container>
|
||||
<NewWikiPathForm
|
||||
parentFolderLocation={parentFolderLocation}
|
||||
parentFolderLocationSetter={parentFolderLocationSetter}
|
||||
wikiFolderName={wikiFolderName}
|
||||
tagName={tagName}
|
||||
tagNameSetter={tagNameSetter}
|
||||
wikiFolderNameSetter={wikiFolderNameSetter}
|
||||
mainWikiToLink={mainWikiToLink}
|
||||
mainWikiToLinkSetter={mainWikiToLinkSetter}
|
||||
wikiPort={wikiPort}
|
||||
wikiPortSetter={wikiPortSetter}
|
||||
fileSystemPaths={fileSystemPaths}
|
||||
isCreateMainWorkspace={isCreateMainWorkspace}
|
||||
/>
|
||||
<NewWikiPathForm form={form} />
|
||||
|
||||
<NewWikiDoneButton
|
||||
isCreateMainWorkspace={isCreateMainWorkspace}
|
||||
wikiPort={wikiPort}
|
||||
mainWikiToLink={mainWikiToLink}
|
||||
githubWikiUrl={githubWikiUrl}
|
||||
wikiFolderName={wikiFolderName}
|
||||
tagName={tagName}
|
||||
parentFolderLocation={parentFolderLocation}
|
||||
userInfo={userInfo}
|
||||
/>
|
||||
<NewWikiDoneButton form={form} />
|
||||
</Container>
|
||||
)}
|
||||
{currentTab === 'OpenLocalWiki' && (
|
||||
<Container>
|
||||
<ExistedWikiPathForm
|
||||
existedFolderLocationSetter={existedFolderLocationSetter}
|
||||
existedFolderLocation={existedFolderLocation}
|
||||
wikiFolderName={wikiFolderName}
|
||||
tagName={tagName}
|
||||
tagNameSetter={tagNameSetter}
|
||||
wikiFolderNameSetter={wikiFolderNameSetter}
|
||||
mainWikiToLink={mainWikiToLink}
|
||||
mainWikiToLinkSetter={mainWikiToLinkSetter}
|
||||
wikiPort={wikiPort}
|
||||
wikiPortSetter={wikiPortSetter}
|
||||
fileSystemPaths={fileSystemPaths}
|
||||
isCreateMainWorkspace={isCreateMainWorkspace}
|
||||
/>
|
||||
<ExistedWikiPathForm form={form} />
|
||||
|
||||
<ExistedWikiDoneButton
|
||||
isCreateMainWorkspace={isCreateMainWorkspace}
|
||||
wikiPort={wikiPort}
|
||||
mainWikiToLink={mainWikiToLink}
|
||||
githubWikiUrl={githubWikiUrl}
|
||||
tagName={tagName}
|
||||
existedFolderLocation={existedFolderLocation}
|
||||
userInfo={userInfo}
|
||||
/>
|
||||
<ExistedWikiDoneButton form={form} />
|
||||
</Container>
|
||||
)}
|
||||
{currentTab === 'CloneOnlineWiki' && (
|
||||
<Container>
|
||||
<NewWikiPathForm
|
||||
parentFolderLocation={parentFolderLocation}
|
||||
parentFolderLocationSetter={parentFolderLocationSetter}
|
||||
wikiFolderName={wikiFolderName}
|
||||
tagName={tagName}
|
||||
tagNameSetter={tagNameSetter}
|
||||
wikiFolderNameSetter={wikiFolderNameSetter}
|
||||
mainWikiToLink={mainWikiToLink}
|
||||
mainWikiToLinkSetter={mainWikiToLinkSetter}
|
||||
wikiPort={wikiPort}
|
||||
wikiPortSetter={wikiPortSetter}
|
||||
fileSystemPaths={fileSystemPaths}
|
||||
isCreateMainWorkspace={isCreateMainWorkspace}
|
||||
/>
|
||||
<CloneWikiDoneButton
|
||||
isCreateMainWorkspace={isCreateMainWorkspace}
|
||||
wikiPort={wikiPort}
|
||||
mainWikiToLink={mainWikiToLink}
|
||||
githubWikiUrl={githubWikiUrl}
|
||||
wikiFolderName={wikiFolderName}
|
||||
tagName={tagName}
|
||||
parentFolderLocation={parentFolderLocation}
|
||||
userInfo={userInfo}
|
||||
/>
|
||||
<NewWikiPathForm form={form} />
|
||||
<CloneWikiDoneButton form={form} />
|
||||
</Container>
|
||||
)}
|
||||
</ClientContext.Provider>
|
||||
|
|
|
|||
|
|
@ -1,44 +0,0 @@
|
|||
import React from 'react';
|
||||
import { invert } from 'lodash';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import Paper from '@material-ui/core/Paper';
|
||||
import AppBar from '@material-ui/core/AppBar';
|
||||
import Tabs from '@material-ui/core/Tabs';
|
||||
import Tab from '@material-ui/core/Tab';
|
||||
|
||||
function a11yProps(index: any) {
|
||||
return {
|
||||
id: index,
|
||||
'aria-controls': `simple-tabpanel-${index}`,
|
||||
};
|
||||
}
|
||||
|
||||
const tabIndexMap = {
|
||||
CloneOnlineWiki: 0,
|
||||
CreateNewWiki: 1,
|
||||
OpenLocalWiki: 2,
|
||||
};
|
||||
|
||||
export interface IProps {
|
||||
currentTab: string;
|
||||
currentTabSetter: (id: string) => void;
|
||||
}
|
||||
export default function TabBar({ currentTab, currentTabSetter }: IProps) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<AppBar position="static">
|
||||
<Paper square>
|
||||
<Tabs
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
value={tabIndexMap[currentTab]}
|
||||
onChange={(event, newValue) => currentTabSetter(invert(tabIndexMap)[newValue])}
|
||||
aria-label={t('AddWorkspace.SwitchCreateNewOrOpenExisted')}>
|
||||
<Tab label={t('AddWorkspace.CloneOnlineWiki')} {...a11yProps('CloneOnlineWiki')} />
|
||||
<Tab label={t('AddWorkspace.CreateNewWiki')} {...a11yProps('CreateNewWiki')} />
|
||||
<Tab label={t('AddWorkspace.OpenLocalWiki')} {...a11yProps('OpenLocalWiki')} />
|
||||
</Tabs>
|
||||
</Paper>
|
||||
</AppBar>
|
||||
);
|
||||
}
|
||||
18
src/pages/AddWorkspace/useCloneWiki.ts
Normal file
18
src/pages/AddWorkspace/useCloneWiki.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import { useCallback } from 'react';
|
||||
export function useCloneWiki(): [() => void] {
|
||||
const onSubmit = useCallback(async () => {
|
||||
if (!userInfo) {
|
||||
setWikiCreationMessage(t('AddWorkspace.NotLoggedIn'));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await window.service.wiki.cloneWiki(parentFolderLocation, wikiFolderName, githubWikiUrl, userInfo);
|
||||
save(workspaceFormData);
|
||||
} catch (error) {
|
||||
setWikiCreationMessage(String(error));
|
||||
}
|
||||
});
|
||||
|
||||
return [onSubmit];
|
||||
}
|
||||
105
src/pages/AddWorkspace/useForm.ts
Normal file
105
src/pages/AddWorkspace/useForm.ts
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { usePromiseValueAndSetter } from '@/helpers/useServiceValue';
|
||||
import { SupportedStorageServices } from '@services/types';
|
||||
import { ISubWikiPluginContent } from '@services/wiki/update-plugin-content';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
export function useIsCreateMainWorkspace(): [boolean, React.Dispatch<React.SetStateAction<boolean>>] {
|
||||
const [isCreateMainWorkspace, isCreateMainWorkspaceSetter] = useState(false);
|
||||
useEffect(() => {
|
||||
void window.service.workspace.countWorkspaces().then((workspaceCount) => isCreateMainWorkspaceSetter(workspaceCount === 0));
|
||||
}, []);
|
||||
return [isCreateMainWorkspace, isCreateMainWorkspaceSetter];
|
||||
}
|
||||
|
||||
export function useWikiWorkspaceForm() {
|
||||
const [wikiPort, wikiPortSetter] = useState(5212);
|
||||
useEffect(() => {
|
||||
// only update default port on component mount
|
||||
void window.service.workspace.countWorkspaces().then((workspaceCount) => wikiPortSetter(wikiPort + workspaceCount));
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Set storage service used by this workspace, for example, Github.
|
||||
*/
|
||||
const [storageProvider, storageProviderSetter] = useState<SupportedStorageServices>(SupportedStorageServices.github);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const [userName, userNameSetter] = usePromiseValueAndSetter(
|
||||
async () => await window.service.auth.get('userName'),
|
||||
async (newUserName) => await window.service.auth.set('userName', newUserName),
|
||||
);
|
||||
|
||||
/**
|
||||
* For sub-wiki, we need to link it to a main wiki's folder, so all wiki contents can be loaded together.
|
||||
*/
|
||||
const [mainWikiToLink, mainWikiToLinkSetter] = useState({ name: '', port: 0 });
|
||||
const [tagName, tagNameSetter] = useState<string>('');
|
||||
/**
|
||||
* For sub-wiki, we need `fileSystemPaths` which is a TiddlyWiki concept that tells wiki where to put sub-wiki files.
|
||||
*/
|
||||
const [fileSystemPaths, fileSystemPathsSetter] = useState<ISubWikiPluginContent[]>([]);
|
||||
useEffect(() => {
|
||||
void window.service.wiki.getSubWikiPluginContent(mainWikiToLink.name).then(fileSystemPathsSetter);
|
||||
}, [mainWikiToLink]);
|
||||
/**
|
||||
* For importing existed nodejs wiki into TiddlyGit, we use existedWikiFolderPath to determine which folder to import
|
||||
*/
|
||||
const [existedWikiFolderPath, existedWikiFolderPathSetter] = useState<string | undefined>();
|
||||
/**
|
||||
* For creating new wiki, we use parentFolderLocation to determine in which folder we create the new wiki folder.
|
||||
* New folder will basically be created in `${parentFolderLocation}/${wikiFolderName}`
|
||||
*/
|
||||
const [parentFolderLocation, parentFolderLocationSetter] = useState<string | undefined>();
|
||||
/**
|
||||
* For creating new wiki, we put `tiddlers` folder in this `${parentFolderLocation}/${wikiFolderName}` folder
|
||||
*/
|
||||
const [wikiFolderName, wikiFolderNameSetter] = useState('tiddlywiki');
|
||||
|
||||
useEffect(() => {
|
||||
void (async function getDefaultExistedWikiFolderPathEffect() {
|
||||
const desktopPathAsDefaultExistedWikiFolderPath = (await window.service.context.get('DESKTOP_PATH')) as string;
|
||||
existedWikiFolderPathSetter(desktopPathAsDefaultExistedWikiFolderPath);
|
||||
parentFolderLocationSetter(desktopPathAsDefaultExistedWikiFolderPath);
|
||||
})();
|
||||
}, [mainWikiToLink]);
|
||||
const [githubWikiUrl, githubWikiUrlSetter] = useState<string>('');
|
||||
|
||||
useEffect(() => {
|
||||
void (async function getWorkspaceRemoteEffect(): Promise<void> {
|
||||
if (existedWikiFolderPath !== undefined) {
|
||||
const url = await window.service.git.getWorkspacesRemote(existedWikiFolderPath);
|
||||
if (typeof url === 'string' && url.length > 0) {
|
||||
githubWikiUrlSetter(url);
|
||||
}
|
||||
}
|
||||
})();
|
||||
}, [githubWikiUrlSetter, existedWikiFolderPath]);
|
||||
|
||||
return {
|
||||
storageProvider,
|
||||
storageProviderSetter,
|
||||
wikiPort,
|
||||
wikiPortSetter,
|
||||
userName,
|
||||
userNameSetter,
|
||||
mainWikiToLink,
|
||||
mainWikiToLinkSetter,
|
||||
tagName,
|
||||
tagNameSetter,
|
||||
fileSystemPaths,
|
||||
fileSystemPathsSetter,
|
||||
githubWikiUrl,
|
||||
githubWikiUrlSetter,
|
||||
existedWikiFolderPath,
|
||||
existedWikiFolderPathSetter,
|
||||
parentFolderLocation,
|
||||
parentFolderLocationSetter,
|
||||
wikiFolderName,
|
||||
wikiFolderNameSetter,
|
||||
};
|
||||
}
|
||||
|
|
@ -22,7 +22,7 @@ import type { ISubWikiPluginContent } from '@services/wiki/update-plugin-content
|
|||
import { WindowNames, WindowMeta } from '@services/windows/WindowProperties';
|
||||
import { usePromiseValue } from '@/helpers/useServiceValue';
|
||||
import { useWorkspaceObservable } from '@services/workspaces/hooks';
|
||||
import { useForm } from './formHook';
|
||||
import { useForm } from './useForm';
|
||||
import { IWorkspace } from '@services/workspaces/interface';
|
||||
|
||||
const Root = styled.div`
|
||||
|
|
|
|||
|
|
@ -1,21 +1,11 @@
|
|||
import { compact, trim } from 'lodash';
|
||||
import { trim } from 'lodash';
|
||||
import { GitProcess } from 'dugite';
|
||||
import { getRemoteUrl } from './inspect';
|
||||
|
||||
const getGitUrlWithCredential = (rawUrl: string, username: string, accessToken: string): string =>
|
||||
trim(`${rawUrl}.git`.replace(/\n/g, '').replace('https://github.com/', `https://${username}:${accessToken}@github.com/`));
|
||||
const getGitUrlWithOutCredential = (urlWithCredential: string): string => trim(urlWithCredential.replace(/.+@/, 'https://'));
|
||||
|
||||
export async function getRemoteUrl(wikiFolderPath: string): Promise<string> {
|
||||
const { stdout: remoteStdout } = await GitProcess.exec(['remote'], wikiFolderPath);
|
||||
const remotes = compact(remoteStdout.split('\n'));
|
||||
const githubRemote = remotes.find((remote) => remote === 'origin') ?? remotes[0] ?? '';
|
||||
if (githubRemote.length > 0) {
|
||||
const { stdout: remoteUrlStdout } = await GitProcess.exec(['remote', 'get-url', githubRemote], wikiFolderPath);
|
||||
return remoteUrlStdout.replace('.git', '');
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Add remote with credential
|
||||
* @param {string} wikiFolderPath
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import type { IViewService } from '@services/view/interface';
|
|||
import type { IPreferenceService } from '@services/preferences/interface';
|
||||
import { logger } from '@services/libs/log';
|
||||
import i18n from '@services/libs/i18n';
|
||||
import { getModifiedFileList, ModifiedFileList } from './inspect';
|
||||
import { getModifiedFileList, ModifiedFileList, getRemoteUrl } from './inspect';
|
||||
import { IGitService, IGitUserInfos } from './interface';
|
||||
|
||||
@injectable()
|
||||
|
|
@ -29,7 +29,7 @@ export class Git implements IGitService {
|
|||
public debounceCommitAndSync: (wikiFolderPath: string, githubRepoUrl: string, userInfo: IGitUserInfos) => Promise<void> | undefined;
|
||||
|
||||
public async getWorkspacesRemote(wikiFolderPath: string): Promise<string> {
|
||||
return await github.getRemoteUrl(wikiFolderPath);
|
||||
return await getRemoteUrl(wikiFolderPath);
|
||||
}
|
||||
|
||||
public async getModifiedFileList(wikiFolderPath: string): Promise<ModifiedFileList[]> {
|
||||
|
|
|
|||
|
|
@ -20,3 +20,19 @@ export async function getModifiedFileList(wikiFolderPath: string): Promise<Modif
|
|||
filePath: path.join(wikiFolderPath, fileRelativePath),
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Inspect git's remote url from folder's .git config
|
||||
* @param wikiFolderPath git folder to inspect
|
||||
* @returns remote url
|
||||
*/
|
||||
export async function getRemoteUrl(wikiFolderPath: string): Promise<string> {
|
||||
const { stdout: remoteStdout } = await GitProcess.exec(['remote'], wikiFolderPath);
|
||||
const remotes = compact(remoteStdout.split('\n'));
|
||||
const githubRemote = remotes.find((remote) => remote === 'origin') ?? remotes[0] ?? '';
|
||||
if (githubRemote.length > 0) {
|
||||
const { stdout: remoteUrlStdout } = await GitProcess.exec(['remote', 'get-url', githubRemote], wikiFolderPath);
|
||||
return remoteUrlStdout.replace('.git', '');
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ export interface IGitService {
|
|||
getModifiedFileList(wikiFolderPath: string): Promise<ModifiedFileList[]>;
|
||||
initWikiGit(wikiFolderPath: string, githubRepoUrl: string, userInfo: IGitUserInfos, isMainWiki: boolean): Promise<void>;
|
||||
commitAndSync(wikiFolderPath: string, githubRepoUrl: string, userInfo: IGitUserInfos): Promise<void>;
|
||||
/** Inspect git's remote url from folder's .git config */
|
||||
getWorkspacesRemote(wikiFolderPath: string): Promise<string>;
|
||||
clone(githubRepoUrl: string, repoFolderPath: string, userInfo: IGitUserInfos): Promise<void>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,13 +3,14 @@ export interface IService {
|
|||
}
|
||||
|
||||
export enum SupportedStorageServices {
|
||||
local = 'local',
|
||||
/** High availability git service without storage limit, but is blocked by GFW in China somehow */
|
||||
github,
|
||||
github = 'github',
|
||||
/** SocialLinkedData, a privacy first DApp platform leading by Tim Berners-Lee, you can run a server by you own */
|
||||
solid,
|
||||
solid = 'solid',
|
||||
/** China's Collaboration platform for software development & code hosting,
|
||||
* with some official background, very secure in China, but have 500M storage limit */
|
||||
gitee,
|
||||
gitee = 'gitee',
|
||||
}
|
||||
|
||||
export interface IAuthingResponse {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue