```
{
"API_HOST": "string",
- "VOCABULARY_URL": "string",
"FILE_VIEWERS_CONFIG_URL": "string",
}
```
The `REACT_APP_ARVADOS_API_HOST` environment variable can be used to set the default URL if the run time configuration is unreachable.
-### VOCABULARY_URL
-Local path, or any URL that allows cross-origin requests. See
-[Vocabulary JSON file example](public/vocabulary-example.json).
-
-To use the URL defined in the Arvados cluster configuration, remove the entire `VOCABULARY_URL` entry from the runtime configuration. Found in `/config.json` by default.
-
## FILE_VIEWERS_CONFIG_URL
Local path, or any URL that allows cross-origin requests. See:
});
// Confirm proper vocabulary labels are displayed on the UI.
cy.get('[data-cy=collection-properties-panel]')
- .should('contain', 'Color')
- .and('contain', 'Magenta');
+ .should('contain', 'Color: Magenta');
// Confirm proper vocabulary IDs were saved on the backend.
cy.doRequest('GET', `/arvados/v1/collections/${this.testCollection.uuid}`)
.its('body').as('collection')
.then(function () {
expect(this.collection.properties.IDTAGCOLORS).to.equal('IDVALCOLORS3');
});
+
+ // Case-insensitive on-blur auto-selection test
+ // Key: Size (IDTAGSIZES) - Value: Small (IDVALSIZES2)
+ cy.get('[data-cy=resource-properties-form]').within(() => {
+ cy.get('[data-cy=property-field-key]').within(() => {
+ cy.get('input').type('sIzE');
+ });
+ cy.get('[data-cy=property-field-value]').within(() => {
+ cy.get('input').type('sMaLL');
+ });
+ // Cannot "type()" TAB on Cypress so let's click another field
+ // to trigger the onBlur event.
+ cy.get('[data-cy=property-field-key]').click();
+ cy.root().submit();
+ });
+ // Confirm proper vocabulary labels are displayed on the UI.
+ cy.get('[data-cy=collection-properties-panel]')
+ .should('contain', 'Size: S');
+ // Confirm proper vocabulary IDs were saved on the backend.
+ cy.doRequest('GET', `/arvados/v1/collections/${this.testCollection.uuid}`)
+ .its('body').as('collection')
+ .then(function () {
+ expect(this.collection.properties.IDTAGSIZES).to.equal('IDVALSIZES2');
+ });
});
});
};
Workbench: {
ArvadosDocsite: string;
- VocabularyURL: string;
FileViewersConfigURL: string;
WelcomePageHTML: string;
InactivePageHTML: string;
}
config.fileViewersConfigUrl = fileViewerConfigUrl;
- let vocabularyUrl;
if (workbenchConfig.VOCABULARY_URL !== undefined) {
- warnLocalConfig("VOCABULARY_URL");
- vocabularyUrl = workbenchConfig.VOCABULARY_URL;
+ console.warn(`A value for VOCABULARY_URL was found in ${WORKBENCH_CONFIG_URL}. It will be ignored as the cluster already provides its own endpoint, you can safely remove it.`)
}
- else {
- vocabularyUrl = config.clusterConfig.Workbench.VocabularyURL || "/vocabulary-example.json";
- }
- config.vocabularyUrl = vocabularyUrl;
+ config.vocabularyUrl = getVocabularyURL(workbenchConfig.API_HOST);
return { config, apiHost: workbenchConfig.API_HOST };
});
},
Workbench: {
ArvadosDocsite: "",
- VocabularyURL: "",
FileViewersConfigURL: "",
WelcomePageHTML: "",
InactivePageHTML: "",
export const ARVADOS_API_PATH = "arvados/v1";
export const CLUSTER_CONFIG_PATH = "arvados/v1/config";
+export const VOCABULARY_PATH = "arvados/v1/vocabulary";
export const DISCOVERY_DOC_PATH = "discovery/v1/apis/arvados/v1/rest";
-export const getClusterConfigURL = (apiHost: string) => `${window.location.protocol}//${apiHost}/${CLUSTER_CONFIG_PATH}?nocache=${(new Date()).getTime()}`;
+export const getClusterConfigURL = (apiHost: string) => `https://${apiHost}/${CLUSTER_CONFIG_PATH}?nocache=${(new Date()).getTime()}`;
+export const getVocabularyURL = (apiHost: string) => `https://${apiHost}/${VOCABULARY_PATH}?nocache=${(new Date()).getTime()}`;
(tagKeyID && vocabulary.tags[tagKeyID] && vocabulary.tags[tagKeyID].values)
? Object.keys(vocabulary.tags[tagKeyID].values!).find(
k => vocabulary.tags[tagKeyID].values![k].labels.find(
- l => l.label === tagValueLabel) !== undefined) || ''
+ l => l.label.toLowerCase() === tagValueLabel.toLowerCase()) !== undefined) || ''
: '';
export const getTagValueLabel = (tagKeyID:string, tagValueID:string, vocabulary: Vocabulary) =>
export const getTagKeyID = (tagKeyLabel:string, vocabulary: Vocabulary) =>
Object.keys(vocabulary.tags).find(
k => vocabulary.tags[k].labels.find(
- l => l.label === tagKeyLabel) !== undefined
+ l => l.label.toLowerCase() === tagKeyLabel.toLowerCase()) !== undefined
) || '';
export const getTagKeyLabel = (tagKeyID:string, vocabulary: Vocabulary) =>
private url: string
) { }
- getVocabulary() {
- return Axios
- .get<Vocabulary>(this.url)
- .then(response => response.data);
+ async getVocabulary() {
+ const response = await Axios
+ .get<Vocabulary>(this.url);
+ return response.data;
}
}
export const loadVocabulary = async (dispatch: Dispatch, _: {}, { vocabularyService }: ServiceRepository) => {
const vocabulary = await vocabularyService.getVocabulary();
-
dispatch(propertiesActions.SET_PROPERTY({
key: VOCABULARY_PROPERTY_NAME,
value: isVocabulary(vocabulary)
import { WrappedFieldProps, Field, FormName, reset, change, WrappedFieldInputProps, WrappedFieldMetaProps } from 'redux-form';
import { memoize } from 'lodash';
import { Autocomplete } from 'components/autocomplete/autocomplete';
-import { Vocabulary, getTags, getTagKeyID } from 'models/vocabulary';
+import { Vocabulary, getTags, getTagKeyID, getTagKeyLabel } from 'models/vocabulary';
import {
handleSelect,
handleBlur,
label='Key'
suggestions={getSuggestions(props.input.value, vocabulary)}
onSelect={handleSelect(PROPERTY_KEY_FIELD_ID, data.form, props.input, props.meta)}
- onBlur={handleBlur(PROPERTY_KEY_FIELD_ID, data.form, props.meta, props.input, getTagKeyID(props.input.value, vocabulary))}
+ onBlur={() => {
+ // Case-insensitive search for the key in the vocabulary
+ const foundKeyID = getTagKeyID(props.input.value, vocabulary);
+ if (foundKeyID !== '') {
+ props.input.value = getTagKeyLabel(foundKeyID, vocabulary);
+ }
+ handleBlur(PROPERTY_KEY_FIELD_ID, data.form, props.meta, props.input, foundKeyID)();
+ }}
onChange={(e: ChangeEvent<HTMLInputElement>) => {
const newValue = e.currentTarget.value;
handleChange(data.form, props.input, props.meta, newValue);
import { WrappedFieldProps, Field, formValues, FormName, WrappedFieldInputProps, WrappedFieldMetaProps, change } from 'redux-form';
import { compose } from 'redux';
import { Autocomplete } from 'components/autocomplete/autocomplete';
-import { Vocabulary, isStrictTag, getTagValues, getTagValueID } from 'models/vocabulary';
+import { Vocabulary, isStrictTag, getTagValues, getTagValueID, getTagValueLabel } from 'models/vocabulary';
import { PROPERTY_KEY_FIELD_ID, PROPERTY_KEY_FIELD_NAME } from 'views-components/resource-properties-form/property-key-field';
import {
handleSelect,
disabled={props.disabled}
suggestions={getSuggestions(props.input.value, propertyKeyId, vocabulary)}
onSelect={handleSelect(PROPERTY_VALUE_FIELD_ID, data.form, props.input, props.meta)}
- onBlur={handleBlur(PROPERTY_VALUE_FIELD_ID, data.form, props.meta, props.input, getTagValueID(propertyKeyId, props.input.value, vocabulary))}
+ onBlur={() => {
+ // Case-insensitive search for the value in the vocabulary
+ const foundValueID = getTagValueID(propertyKeyId, props.input.value, vocabulary);
+ if (foundValueID !== '') {
+ props.input.value = getTagValueLabel(propertyKeyId, foundValueID, vocabulary);
+ }
+ handleBlur(PROPERTY_VALUE_FIELD_ID, data.form, props.meta, props.input, foundValueID)();
+ }}
onChange={(e: ChangeEvent<HTMLInputElement>) => {
const newValue = e.currentTarget.value;
const tagValueID = getTagValueID(propertyKeyId, newValue, vocabulary);
SystemRootToken: systemusertesttoken1234567890aoeuidhtnsqjkxbmwvzpy
API:
RequestTimeout: 30s
+ VocabularyPath: ""
TLS:
Insecure: true
Collections:
ARVADOS_LOG=${ARVADOS_DIR}/arvados.log
ARVADOS_CONF=${WB2_DIR}/tools/arvados_config.yml
+VOCABULARY_CONF=${WB2_DIR}/tools/example-vocabulary.json
if [ ! -f "${WB2_DIR}/src/index.tsx" ]; then
echo "ERROR: '${WB2_DIR}' isn't workbench2's directory"
~/go/bin/arvados-server install -type test || exit 1
echo "Launching arvados in test mode..."
+VOC_DIR=$(mktemp -d | cut -d \/ -f3) # Removes the /tmp/ part
+cp ${VOCABULARY_CONF} /tmp/${VOC_DIR}/voc.json
+sed -i "s/VocabularyPath: \".*\"/VocabularyPath: \"\/tmp\/${VOC_DIR}\/voc.json\"/" ${ARVADOS_CONF}
coproc arvboot (~/go/bin/arvados-server boot \
-type test \
-config ${ARVADOS_CONF} \