mirror of
https://github.com/tiddly-gittly/TidGi-Desktop.git
synced 2026-01-24 13:30:59 -08:00
* feat: basic git gui using @tomplum/react-git-log * Replace menu bar toggle with mini window shortcut Removed the menu bar toggle option and its Windows-specific logic from the View menu. Added a new menu item for toggling the Tidgi mini window, using a configurable keyboard shortcut from preferences. * update i18n * refactor: use table for default view for cleaner timeline * test: commit * Add realtime git log updates and e2e test support Implements detection and display of uncommitted changes in the Git Log window, adds a commit button for uncommitted changes, and refreshes data in response to git state changes using an observable. Adds e2e test step definitions and log markers for commit, revert, and checkout operations to support automated testing. Removes alert popups from commit, revert, and checkout actions in the UI. * refactor: steps with descripton * fix: watch fs on git checkout * fix: echo of file on start * feat: loading state on revert * feat: ai commit message * feat: check free model * fix: remove duplicated backup action * fix: git method wrong place * fix: model not auto filled * refactor: preload $:/info/tidgi/workspaceID by 'module-type': 'info', * fix: workspace context menu * fix: show correct menu on view * feat: let tooltip show files instead of hash * feat: view dark theme * feat: better diff ui, and upgrade dugite * Update aiCommitMessage.ts * Update gitLog.feature * fix: menu click test * fix: The isInitialLoad check is computed twice * fix: import wiki form cursor position wrong * fix: git log frequently load data * fix: hide wiki menu * fix: import wiki form not working * fix: timer not cleared * onBlur handler that resets the field to the current valid preference value * fix: review error * Update useGitLogData.ts * Update newAgent.feature * Update newAgent.feature * fix: test randomly fail * fix * fix * Update wiki.ts * fix: wait for mark * Git-Sync-JS logger fix * Git-Sync-JS more logs * Git-sync-js fix no commiter email * Update gitOperations.ts
155 lines
6.1 KiB
TypeScript
155 lines
6.1 KiB
TypeScript
import FolderIcon from '@mui/icons-material/Folder';
|
|
import { AutocompleteRenderInputParams, MenuItem, Typography } from '@mui/material';
|
|
import { useCallback, useState } from 'react';
|
|
import { useTranslation } from 'react-i18next';
|
|
|
|
import { isWikiWorkspace } from '@services/workspaces/interface';
|
|
import { CreateContainer, LocationPickerButton, LocationPickerContainer, LocationPickerInput, SoftLinkToMainWikiSelect, SubWikiTagAutoComplete } from './FormComponents';
|
|
|
|
import { useAvailableTags } from './useAvailableTags';
|
|
import { useValidateExistedWiki } from './useExistedWiki';
|
|
import type { IWikiWorkspaceFormProps } from './useForm';
|
|
|
|
export function ExistedWikiForm({
|
|
form,
|
|
isCreateMainWorkspace,
|
|
isCreateSyncedWorkspace,
|
|
errorInWhichComponent,
|
|
errorInWhichComponentSetter,
|
|
}: IWikiWorkspaceFormProps & { isCreateSyncedWorkspace: boolean }): React.JSX.Element {
|
|
const { t } = useTranslation();
|
|
|
|
// Fetch all tags from main wiki for autocomplete suggestions
|
|
const availableTags = useAvailableTags(form.mainWikiToLink.id, !isCreateMainWorkspace);
|
|
|
|
const {
|
|
wikiFolderLocation,
|
|
wikiFolderNameSetter,
|
|
parentFolderLocation,
|
|
parentFolderLocationSetter,
|
|
mainWikiToLink,
|
|
wikiFolderName,
|
|
mainWikiToLinkIndex,
|
|
mainWikiToLinkSetter,
|
|
mainWorkspaceList,
|
|
tagName,
|
|
tagNameSetter,
|
|
} = form;
|
|
|
|
// Local state for the full path input - like NewWikiForm's direct state binding
|
|
// Initialize from form values
|
|
const [fullPath, setFullPath] = useState(() => {
|
|
if (parentFolderLocation && wikiFolderName) {
|
|
return `${parentFolderLocation}${parentFolderLocation.endsWith('/') || parentFolderLocation.endsWith('\\') ? '' : '/'}${wikiFolderName}`;
|
|
}
|
|
return '';
|
|
});
|
|
|
|
useValidateExistedWiki(isCreateMainWorkspace, isCreateSyncedWorkspace, form, errorInWhichComponentSetter);
|
|
|
|
const onLocationChange = useCallback(
|
|
async (newLocation: string) => {
|
|
const folderName = await window.service.native.path('basename', newLocation);
|
|
const directoryName = await window.service.native.path('dirname', newLocation);
|
|
if (folderName !== undefined && directoryName !== undefined) {
|
|
wikiFolderNameSetter(folderName);
|
|
parentFolderLocationSetter(directoryName);
|
|
// Update local state
|
|
setFullPath(newLocation);
|
|
}
|
|
},
|
|
[wikiFolderNameSetter, parentFolderLocationSetter],
|
|
);
|
|
return (
|
|
<CreateContainer elevation={2} square>
|
|
<LocationPickerContainer>
|
|
<LocationPickerInput
|
|
error={errorInWhichComponent.wikiFolderLocation}
|
|
onChange={(event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
|
// Update local state immediately for responsive UI
|
|
const newValue = event.target.value;
|
|
setFullPath(newValue);
|
|
|
|
// Parse path into parent and folder for validation
|
|
const lastSlashIndex = Math.max(newValue.lastIndexOf('/'), newValue.lastIndexOf('\\'));
|
|
if (lastSlashIndex >= 0) {
|
|
const folder = newValue.slice(lastSlashIndex + 1);
|
|
// Handle root paths: "/" or "C:\"
|
|
const parent = lastSlashIndex === 0 ? '/' : newValue.slice(0, lastSlashIndex);
|
|
wikiFolderNameSetter(folder);
|
|
parentFolderLocationSetter(parent);
|
|
} else {
|
|
// No slash found - treat as relative path or bare folder name
|
|
wikiFolderNameSetter(newValue);
|
|
parentFolderLocationSetter('');
|
|
}
|
|
}}
|
|
label={t('AddWorkspace.WorkspaceFolder')}
|
|
helperText={`${t('AddWorkspace.ImportWiki')}${wikiFolderLocation ?? ''}`}
|
|
value={fullPath}
|
|
/>
|
|
<LocationPickerButton
|
|
onClick={async () => {
|
|
// first clear the text, so button will refresh
|
|
await onLocationChange('');
|
|
const filePaths = await window.service.native.pickDirectory(parentFolderLocation);
|
|
if (filePaths.length > 0) {
|
|
await onLocationChange(filePaths[0]);
|
|
}
|
|
}}
|
|
endIcon={<FolderIcon />}
|
|
>
|
|
<Typography variant='button' display='inline'>
|
|
{t('AddWorkspace.Choose')}
|
|
</Typography>
|
|
</LocationPickerButton>
|
|
</LocationPickerContainer>
|
|
{!isCreateMainWorkspace && (
|
|
<>
|
|
<SoftLinkToMainWikiSelect
|
|
select
|
|
error={errorInWhichComponent.mainWikiToLink}
|
|
label={t('AddWorkspace.MainWorkspaceLocation')}
|
|
helperText={mainWikiToLink.wikiFolderLocation &&
|
|
`${t('AddWorkspace.SubWorkspaceWillLinkTo')}
|
|
${mainWikiToLink.wikiFolderLocation}/tiddlers/${wikiFolderName}`}
|
|
value={mainWikiToLinkIndex}
|
|
onChange={(event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
|
const index = Number(event.target.value);
|
|
const selectedWorkspace = mainWorkspaceList[index];
|
|
if (selectedWorkspace && isWikiWorkspace(selectedWorkspace)) {
|
|
mainWikiToLinkSetter({
|
|
wikiFolderLocation: selectedWorkspace.wikiFolderLocation,
|
|
port: selectedWorkspace.port,
|
|
id: selectedWorkspace.id,
|
|
});
|
|
}
|
|
}}
|
|
>
|
|
{mainWorkspaceList.map((workspace, index) => (
|
|
<MenuItem key={index} value={index}>
|
|
{workspace.name}
|
|
</MenuItem>
|
|
))}
|
|
</SoftLinkToMainWikiSelect>
|
|
<SubWikiTagAutoComplete
|
|
freeSolo
|
|
options={availableTags}
|
|
value={tagName}
|
|
onInputChange={(_event: React.SyntheticEvent, value: string) => {
|
|
tagNameSetter(value);
|
|
}}
|
|
renderInput={(parameters: AutocompleteRenderInputParams) => (
|
|
<LocationPickerInput
|
|
{...parameters}
|
|
error={errorInWhichComponent.tagName}
|
|
label={t('AddWorkspace.TagName')}
|
|
helperText={t('AddWorkspace.TagNameHelp')}
|
|
/>
|
|
)}
|
|
/>
|
|
</>
|
|
)}
|
|
</CreateContainer>
|
|
);
|
|
}
|