TidGi-Desktop/src/windows/AddWorkspace/ExistedWikiForm.tsx
lin onetwo 3718d0bd39
Fix/edit agent and several bugs (#670)
* 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
2025-12-15 17:33:59 +08:00

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>
);
}