@craftercms/studio-ui
Version:
Services, components, models & utils to build CrafterCMS authoring extensions.
150 lines (148 loc) • 5.89 kB
JavaScript
/*
* Copyright (C) 2007-2022 Crafter Software Corporation. All Rights Reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Copyright (C) 2007-2022 Crafter Software Corporation. All Rights Reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React, { useEffect, useState } from 'react';
import { FormattedMessage } from 'react-intl';
import InputAdornment from '@mui/material/InputAdornment';
import FormHelperText from '@mui/material/FormHelperText';
import FormControl from '@mui/material/FormControl';
import TextField from '@mui/material/TextField';
import { UNDEFINED } from '../../utils/constants';
import { checkPathExistence } from '../../services/content';
import { takeUntil } from 'rxjs/operators';
import useUnmount$ from '../../hooks/useUnmount$';
import useActiveSiteId from '../../hooks/useActiveSiteId';
import CircularProgress from '@mui/material/CircularProgress';
import { CheckRounded, ErrorRounded } from '@mui/icons-material';
import { withoutFile, withoutIndex } from '../../utils/path';
import useUpdateRefs from '../../hooks/useUpdateRefs';
export function PathSelectionInput(props) {
const { rootPath = '', currentPath = '', allowFiles = false, onChange: onChangeProp, startAdornment } = props;
const unmount$ = useUnmount$();
const site = useActiveSiteId();
const [path, setPath] = useState('');
const [pathExists, setPathExists] = useState(null); // null = unchecked
const [isChecking, setIsChecking] = useState(false);
const getFullPath = () => `${rootPath}${path}`.trim();
const check = () => {
setIsChecking(true);
let value = getFullPath();
if (!allowFiles) {
value = withoutFile(value);
}
value = value.replace(/\/$/, '');
setPath(value.substr(rootPath.length));
checkPathExistence(site, value)
.pipe(takeUntil(unmount$))
.subscribe({
next(exists) {
var _a, _b;
setIsChecking(false);
setPathExists(exists);
exists && ((_b = (_a = refs.current).onChange) === null || _b === void 0 ? void 0 : _b.call(_a, value));
},
error() {
setIsChecking(false);
setPathExists(false);
}
});
};
const onKeyPress = (event) => {
if (event.key === 'Enter') {
check();
}
};
const onChange = (event) => {
setPath(event.target.value);
setPathExists(null);
};
const refs = useUpdateRefs({ rootPath, onChange: onChangeProp, getFullPath });
useEffect(() => {
const newPath = withoutIndex(currentPath.startsWith(rootPath) ? currentPath.substr(rootPath.length) : currentPath);
if (`${rootPath}${newPath}` !== refs.current.getFullPath()) {
setPathExists(null);
setIsChecking(false);
setPath(newPath);
}
}, [refs, rootPath, currentPath]);
return React.createElement(
FormControl,
{ sx: { mb: 1 } },
React.createElement(TextField, {
fullWidth: true,
value: path,
onKeyPress: onKeyPress,
onChange: onChange,
error: pathExists === false,
'aria-describedby': 'pathInputTextField',
label: React.createElement(FormattedMessage, { id: 'words.path', defaultMessage: 'Path' }),
InputProps: {
startAdornment: rootPath
? React.createElement(InputAdornment, { position: 'start', sx: { mr: 0 } }, startAdornment, rootPath)
: UNDEFINED,
endAdornment: isChecking
? React.createElement(
InputAdornment,
{ position: 'end', sx: { width: 20, height: 20 } },
React.createElement(CircularProgress, { variant: 'indeterminate', size: 20 })
)
: pathExists === true
? React.createElement(
InputAdornment,
{ position: 'end' },
React.createElement(CheckRounded, { color: 'success' })
)
: pathExists === false
? React.createElement(
InputAdornment,
{ position: 'end' },
React.createElement(ErrorRounded, { color: 'error' })
)
: UNDEFINED
}
}),
React.createElement(
FormHelperText,
{ id: 'pathInputTextFieldHelper', error: pathExists === false },
pathExists
? React.createElement(FormattedMessage, { id: 'pathSelectionInput.found', defaultMessage: 'Path found' })
: pathExists === false
? React.createElement(FormattedMessage, {
id: 'pathSelectionInput.invalidPath',
defaultMessage: "The entered path doesn't exist"
})
: React.createElement(FormattedMessage, {
id: 'pathSelectionInput.description',
defaultMessage: 'Enter a path and press `enter` to validate'
})
)
);
}
export default PathSelectionInput;