mirror of
https://github.com/tiddly-gittly/TidGi-Desktop.git
synced 2026-01-24 05:21:02 -08:00
* refactor: simplify tool writing * feat: load prompt from plugin in a wiki, let agent know what to do based on https://github.com/TiddlyWiki/TiddlyWiki5/issues/9378 * fix: i18n fix: i18n fix: wrong i18n structure fix: empty i18n * Add ContentLoading component and suspense fallback * fix: monaco loading * docs: usage of chrome mcp to contron during dev * fix: provider config truncate user input when typing * fix: legacy usage * Update package.json * fix: not loadin initial data * feat: better prompt sort * fix: sorting of array * fix: drag * Create DragAndDrop.md * feat: directly enter edit mode * fix: workspace config change cause immediate main wiki restart * Add 'Press Enter to confirm' to tag help texts * fix: dont show system tag when adding sub wiki * feat: inform user to press enter on tag auto complete * refactor: let sub wiki auto complete tag * Revert Add 'Press Enter to confirm' to tag help texts * fix: not able to open prompt editor by click prompt tree * fix: click to open plugin config * chore: remove log * feat: Auto-select the first file if none is selected * fix: don't preview not enabled prompt parts * fix: Keep i18n ally think these keys exist, otherwise it will delete them during "check usage" * lint: fix * Update externalAPI.logging.test.ts
172 lines
6.6 KiB
TypeScript
172 lines
6.6 KiB
TypeScript
import FolderIcon from '@mui/icons-material/Folder';
|
|
import { Autocomplete, 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 } 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();
|
|
const [tagInputValue, setTagInputValue] = useState<string>('');
|
|
|
|
// Fetch all tags from main wiki for autocomplete suggestions
|
|
const availableTags = useAvailableTags(form.mainWikiToLink.id, !isCreateMainWorkspace);
|
|
|
|
const tagHelperText = tagInputValue.trim().length > 0
|
|
? t('AddWorkspace.TagNameInputWarning')
|
|
: (isCreateMainWorkspace
|
|
? t('AddWorkspace.TagNameHelpForMain')
|
|
: t('AddWorkspace.TagNameHelp'));
|
|
|
|
const {
|
|
wikiFolderLocation,
|
|
wikiFolderNameSetter,
|
|
parentFolderLocation,
|
|
parentFolderLocationSetter,
|
|
mainWikiToLink,
|
|
wikiFolderName,
|
|
mainWikiToLinkIndex,
|
|
mainWikiToLinkSetter,
|
|
mainWorkspaceList,
|
|
tagNames,
|
|
tagNamesSetter,
|
|
} = 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}`}
|
|
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>
|
|
<Autocomplete<string, true, false, true>
|
|
multiple
|
|
freeSolo
|
|
options={availableTags}
|
|
value={tagNames}
|
|
onInputChange={(_event, newInputValue) => {
|
|
setTagInputValue(newInputValue);
|
|
}}
|
|
onChange={(_event, newValue) => {
|
|
tagNamesSetter(newValue);
|
|
setTagInputValue('');
|
|
}}
|
|
slotProps={{
|
|
chip: {
|
|
variant: 'outlined',
|
|
},
|
|
}}
|
|
renderInput={(parameters: AutocompleteRenderInputParams) => (
|
|
<LocationPickerInput
|
|
{...parameters}
|
|
error={errorInWhichComponent.tagNames}
|
|
label={t('AddWorkspace.TagName')}
|
|
helperText={tagHelperText}
|
|
/>
|
|
)}
|
|
/>
|
|
</>
|
|
)}
|
|
</CreateContainer>
|
|
);
|
|
}
|