Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ISPN-13218 improve error messages on cache creation #158

Merged
merged 1 commit into from Aug 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/__tests__/services/cacheConfigUtils.test.ts
Expand Up @@ -119,4 +119,12 @@ describe('Cache Config Utils tests', () => {
]);
});

test('minim validation of the configuration json or xml', () => {
expect(CacheConfigUtils.validateConfig('').isLeft()).toBeTruthy();
expect(CacheConfigUtils.validateConfig(' ').isLeft()).toBeTruthy();
expect(CacheConfigUtils.validateConfig('xml').isLeft()).toBeTruthy();
expect(CacheConfigUtils.validateConfig('json').isLeft()).toBeTruthy();
expect(CacheConfigUtils.validateConfig('{}').isRight()).toBeTruthy();
expect(CacheConfigUtils.validateConfig('<xml>foo</xml>').isRight()).toBeTruthy();
});
});
45 changes: 20 additions & 25 deletions src/app/Caches/CreateCache.tsx
Expand Up @@ -29,6 +29,7 @@ import {useHistory} from 'react-router';
import {useApiAlert} from '@app/utils/useApiAlert';
import {DataContainerBreadcrumb} from '@app/Common/DataContainerBreadcrumb';
import {ConsoleServices} from "@services/ConsoleServices";
import {CacheConfigUtils} from "@services/cacheConfigUtils";

const CreateCache: React.FunctionComponent<any> = (props) => {
const { addAlert } = useApiAlert();
Expand All @@ -47,6 +48,7 @@ const CreateCache: React.FunctionComponent<any> = (props) => {
const [validConfig, setValidConfig] = useState<
'success' | 'error' | 'default'
>('default');
const [errorConfig, setErrorConfig] = useState('');

interface OptionSelect {
value: string;
Expand Down Expand Up @@ -103,39 +105,31 @@ const CreateCache: React.FunctionComponent<any> = (props) => {
}
};

const validateConfig = (): boolean => {
const trimmedConf = config.trim();
if (trimmedConf.length == 0) {
return false;
}
let isJson = false;
let isXML = false;
try {
JSON.parse(trimmedConf);
isJson = true;
} catch (ex) {}

try {
let oDOM = new DOMParser().parseFromString(trimmedConf, 'text/xml');
if (oDOM.getElementsByTagName('parsererror').length == 0) {
isXML = true;
}
} catch (ex) {}
return isJson || isXML;
};

const createCache = () => {
setErrorConfig('');
const name = cacheName.trim();
// Validate Name
let isValidName: 'success' | 'error' =
name.length > 0 ? 'success' : 'error';
let isValidConfig: 'success' | 'error' =
selectedConfig != '' || validateConfig() ? 'success' : 'error';
setValidName(isValidName);

// Validate the config
let isValidConfig: 'success' | 'error' = 'error';
if (selectedConfig != '') {
isValidConfig = 'success';
} else {
let configValidation = CacheConfigUtils.validateConfig(config);
isValidConfig = configValidation.isRight() ? 'success' : 'error';
if (configValidation.isLeft()) {
setErrorConfig(configValidation.value);
}
}
setValidConfig(isValidConfig);

if (isValidName == 'error' || isValidConfig == 'error') {
return;
}

let createCacheCall: Promise<ActionResponse>;
if (selectedConfig != '') {
createCacheCall = ConsoleServices.caches().createCacheByConfigName(
Expand Down Expand Up @@ -202,9 +196,9 @@ const CreateCache: React.FunctionComponent<any> = (props) => {
<FormGroup
fieldId="cache-config-name"
label="Cache templates"
helperText="Select a cache template or provide a cache configuration."
helperText="Select a cache template or provide a valid cache configuration."
validated={validConfig}
helperTextInvalid="Your cache must have a configuration."
helperTextInvalid={errorConfig}
>
<Select
toggleIcon={<CubeIcon />}
Expand Down Expand Up @@ -238,6 +232,7 @@ const CreateCache: React.FunctionComponent<any> = (props) => {
<FormGroup
label="Cache configuration"
fieldId="cache-config"
validated={validConfig}
helperText="Enter a cache configuration in XML or JSON format."
helperTextInvalid="Provide a valid cache configuration in XML or JSON format."
>
Expand Down
4 changes: 2 additions & 2 deletions src/app/Caches/DetailCache.tsx
Expand Up @@ -79,15 +79,15 @@ const DetailCache = (props: { cacheName: string }) => {
style={{ backgroundColor: 'white' }}
onSelect={(event, tabIndex) => setActiveTabKey2(tabIndex)}
>
<Tab eventKey={10} title={<TabTitleText>{t('caches.actions.action-manage-indexes')}</TabTitleText>}>
<Tab eventKey={10} title={<TabTitleText>{t('caches.tabs.entries-manage')}</TabTitleText>}>
<CacheEntries cacheName={cacheName} />
</Tab>
<Tab
eventKey={13}
title={
<TabTitleText>
<MoreInfoTooltip
label={'Query values in caches.'}
label={t('caches.tabs.query-values')}
toolTip={'Use the Ickle query language to search values.'}
/>
</TabTitleText>
Expand Down
4 changes: 3 additions & 1 deletion src/app/assets/languages/en.json
Expand Up @@ -120,7 +120,9 @@
"configuration": "Configuration",
"metrics": "Metrics ({{status}})",
"metrics-enabled": "Metrics (Enabled)",
"metrics-disabled": "Metrics (Not enabled)"
"metrics-disabled": "Metrics (Not enabled)",
"entries-manage": "Manage entries",
"query-values":"Query values"
},
"info" : {
"breadcrumb" : "Detail of cache {{cacheName}}",
Expand Down
28 changes: 28 additions & 0 deletions src/services/cacheConfigUtils.ts
@@ -1,4 +1,5 @@
import { ContentType, EncodingType } from '@services/infinispanRefData';
import {Either, left, right} from "@services/either";

export const Distributed = 'distributed-cache';
export const Replicated = 'replicated-cache';
Expand All @@ -10,6 +11,33 @@ export const Scattered = 'scattered-cache';
* Utility class to map cache configuration
*/
export class CacheConfigUtils {

/**
* Validates a configuration of cache may have a correct format and detects if it's
* a valid formatted json or a xml.
*
* @param config
*/
public static validateConfig (config: string): Either<string, 'xml' | 'json'> {
const trimmedConf = config.trim();

if (trimmedConf.length == 0) {
return left('Configuration can\'t be empty');
}
try {
JSON.parse(trimmedConf);
return right('json');
} catch (ex) {}

try {
let oDOM = new DOMParser().parseFromString(trimmedConf, 'text/xml');
if (oDOM.getElementsByTagName('parsererror').length == 0) {
return right('xml');
}
} catch (ex) {}
return left('The provided configuration is not a valid XML or JSON.');
};

/**
* Map the encoding type of the cache
* @param config, config of the cache
Expand Down