diff --git a/packages/libs/wdk-client/src/Service/Decoders/QuestionDecoders.ts b/packages/libs/wdk-client/src/Service/Decoders/QuestionDecoders.ts new file mode 100644 index 0000000000..373faaea95 --- /dev/null +++ b/packages/libs/wdk-client/src/Service/Decoders/QuestionDecoders.ts @@ -0,0 +1,389 @@ +import { + Question, + QuestionWithParameters, + TreeBoxVocabNode, + Parameter, + ParameterGroup, + SummaryViewPluginField, + DatasetParam, + TimestampParam, + StringParam, + FilterParamNew, + NumberParam, + NumberRangeParam, + DateParam, + DateRangeParam, + AnswerParam, + EnumParam, + CheckBoxEnumParam, + SinglePickCheckBoxEnumParam, + MultiPickCheckBoxEnumParam, + SinglePickSelectEnumParam, + MultiPickSelectEnumParam, + SelectEnumParam, + SinglePickTypeAheadEnumParam, + MultiPickTypeAheadEnumParam, + TypeAheadEnumParam, + SinglePickTreeBoxEnumParam, + MultiPickTreeBoxEnumParam, + TreeBoxEnumParam, +} from '../../Utils/WdkModel'; +import * as Decode from '../../Utils/Json'; +import { attributeFieldDecoder } from '../Decoders/RecordClassDecoders'; + +const summaryViewPluginFieldDecoder: Decode.Decoder = + Decode.combine( + Decode.field('name', Decode.string), + Decode.field('displayName', Decode.string), + Decode.field('description', Decode.string) + ); + +const questionFilterDecoder = Decode.combine( + Decode.field('name', Decode.string), + Decode.field('displayName', Decode.optional(Decode.string)), + Decode.field('description', Decode.optional(Decode.string)), + Decode.field('isViewOnly', Decode.boolean) +); + +const paramSharedDecoder = + /* Common properties */ + Decode.combine( + Decode.combine( + Decode.field('name', Decode.string), + Decode.field('displayName', Decode.string), + Decode.field( + 'properties', + Decode.optional(Decode.objectOf(Decode.arrayOf(Decode.string))) + ), + Decode.field('help', Decode.string), + Decode.field('isVisible', Decode.boolean), + Decode.field('group', Decode.string), + Decode.field('isReadOnly', Decode.boolean), + Decode.field('initialDisplayValue', Decode.optional(Decode.string)), + Decode.field('dependentParams', Decode.arrayOf(Decode.string)) + ), + Decode.combine( + Decode.field('allowEmptyValue', Decode.boolean), + Decode.field('visibleHelp', Decode.optional(Decode.string)) + ) + ); + +/* DatasetParam */ +const datasetParamDecoder: Decode.Decoder = Decode.combine( + paramSharedDecoder, + Decode.field('type', Decode.constant('input-dataset')), + Decode.field('defaultIdList', Decode.optional(Decode.string)), + Decode.field( + 'parsers', + Decode.arrayOf( + Decode.combine( + Decode.field('name', Decode.string), + Decode.field('displayName', Decode.string), + Decode.field('description', Decode.string) + ) + ) + ) +); + +/* TimestampParam */ +const timestampParamDecoder: Decode.Decoder = Decode.combine( + paramSharedDecoder, + Decode.field('type', Decode.constant('timestamp')) +); + +/* StringParam */ +const stringParamDecoder: Decode.Decoder = Decode.combine( + paramSharedDecoder, + Decode.field('type', Decode.constant('string')), + Decode.field('length', Decode.number) +); + +/* FilterParamNew */ +const filterParamDecoder: Decode.Decoder = Decode.combine( + paramSharedDecoder, + Decode.field('type', Decode.constant('filter')), + Decode.field('filterDataTypeDisplayName', Decode.optional(Decode.string)), + Decode.field('minSelectedCount', Decode.number), + Decode.field('hideEmptyOntologyNodes', Decode.optional(Decode.boolean)), + Decode.field('values', Decode.objectOf(Decode.arrayOf(Decode.string))), + Decode.field( + 'ontology', + Decode.arrayOf( + Decode.combine( + Decode.field('term', Decode.string), + Decode.field('parent', Decode.optional(Decode.string)), + Decode.field('display', Decode.string), + Decode.field('description', Decode.optional(Decode.string)), + Decode.field( + 'type', + Decode.optional( + Decode.oneOf( + Decode.constant('date'), + Decode.constant('string'), + Decode.constant('number'), + Decode.constant('multiFilter') + ) + ) + ), + // Decode.field('units', Decode.string), + Decode.field('precision', Decode.number), + Decode.field('isRange', Decode.boolean) + ) + ) + ) +); + +/* NumberParam */ +const numberParamDecoder: Decode.Decoder = Decode.combine( + paramSharedDecoder, + Decode.field('type', Decode.constant('number')), + Decode.field('min', Decode.number), + Decode.field('max', Decode.number), + Decode.field('increment', Decode.number) +); + +/* NumberRangeParam */ +const numberRangeParamDecoder: Decode.Decoder = + Decode.combine( + paramSharedDecoder, + Decode.field('type', Decode.constant('number-range')), + Decode.field('min', Decode.number), + Decode.field('max', Decode.number), + Decode.field('increment', Decode.number) + ); + +/* DateParam */ +const dateParamDecoder: Decode.Decoder = Decode.combine( + paramSharedDecoder, + Decode.field('type', Decode.constant('date')), + Decode.field('minDate', Decode.string), + Decode.field('maxDate', Decode.string) +); + +/* DateRangeParam */ +const dateRangeParamDecoder: Decode.Decoder = Decode.combine( + paramSharedDecoder, + Decode.field('type', Decode.constant('date-range')), + Decode.field('minDate', Decode.string), + Decode.field('maxDate', Decode.string) +); + +/* AnswerParam */ +const answerParamDecoder: Decode.Decoder = Decode.combine( + paramSharedDecoder, + Decode.field('type', Decode.constant('input-step')) +); + +/* Base decoders for enum types */ +const enumParamSharedDecoder = Decode.combine( + paramSharedDecoder, + Decode.field('maxSelectedCount', Decode.number), + Decode.field('minSelectedCount', Decode.number) +); + +const singlePickEnumParamDecoder = Decode.field( + 'type', + Decode.constant('single-pick-vocabulary') +); +const multiPickEnumParamDecoder = Decode.field( + 'type', + Decode.constant('multi-pick-vocabulary') +); + +const standardVocabularyEnumParamDecoder = Decode.combine( + enumParamSharedDecoder, + Decode.field( + 'vocabulary', + Decode.arrayOf(Decode.tuple(Decode.string, Decode.string, Decode.nullValue)) + ) +); + +/* CheckBoxEnumParam */ +const checkBoxEnumParamBaseDecoder = Decode.combine( + standardVocabularyEnumParamDecoder, + Decode.field('displayType', Decode.constant('checkBox')) +); +export const singlePickCheckBoxEnumParamDecoder: Decode.Decoder = + Decode.combine(checkBoxEnumParamBaseDecoder, singlePickEnumParamDecoder); +export const multiPickCheckBoxEnumParamDecoder: Decode.Decoder = + Decode.combine(checkBoxEnumParamBaseDecoder, multiPickEnumParamDecoder); +export const checkBoxEnumParamDecoder: Decode.Decoder = + Decode.oneOf( + singlePickCheckBoxEnumParamDecoder, + multiPickCheckBoxEnumParamDecoder + ); + +/* SelectEnumParam */ +const selectEnumParamBaseDecoder = Decode.combine( + standardVocabularyEnumParamDecoder, + Decode.field('displayType', Decode.constant('select')) +); +export const singlePickSelectEnumParamDecoder: Decode.Decoder = + Decode.combine(selectEnumParamBaseDecoder, singlePickEnumParamDecoder); +export const multiPickSelectEnumParamDecoder: Decode.Decoder = + Decode.combine(selectEnumParamBaseDecoder, multiPickEnumParamDecoder); +export const selectEnumParamDecoder: Decode.Decoder = + Decode.oneOf( + singlePickSelectEnumParamDecoder, + multiPickSelectEnumParamDecoder + ); + +/* TypeAheadEnumParam */ +const typeAheadEnumParamBaseDecoder = Decode.combine( + standardVocabularyEnumParamDecoder, + Decode.field('displayType', Decode.constant('typeAhead')) +); +export const singlePickTypeAheadEnumParamDecoder: Decode.Decoder = + Decode.combine(typeAheadEnumParamBaseDecoder, singlePickEnumParamDecoder); +export const multiPickTypeAheadEnumParamDecoder: Decode.Decoder = + Decode.combine(typeAheadEnumParamBaseDecoder, multiPickEnumParamDecoder); +export const typeAheadEnumParamDecoder: Decode.Decoder = + Decode.oneOf( + singlePickTypeAheadEnumParamDecoder, + multiPickTypeAheadEnumParamDecoder + ); + +/* TreeboxEnumParam */ +const treeBoxVocabDecoder: Decode.Decoder = Decode.combine( + Decode.field( + 'data', + Decode.combine( + Decode.field('term', Decode.string), + Decode.field('display', Decode.string) + ) + ), + Decode.field( + 'children', + Decode.lazy(() => Decode.arrayOf(treeBoxVocabDecoder)) + ) +); +const treeBoxEnumParamBaseDecoder = Decode.combine( + enumParamSharedDecoder, + Decode.field('displayType', Decode.constant('treeBox')), + Decode.field('countOnlyLeaves', Decode.boolean), + Decode.field('depthExpanded', Decode.number), + Decode.field('vocabulary', treeBoxVocabDecoder) +); +export const singlePickTreeBoxEnumParamDecoder: Decode.Decoder = + Decode.combine(treeBoxEnumParamBaseDecoder, singlePickEnumParamDecoder); +export const multiPickTreeBoxEnumParamDecoder: Decode.Decoder = + Decode.combine(treeBoxEnumParamBaseDecoder, multiPickEnumParamDecoder); +export const treeBoxEnumParamDecoder: Decode.Decoder = + Decode.oneOf( + singlePickTreeBoxEnumParamDecoder, + multiPickTreeBoxEnumParamDecoder + ); + +/* EnumParam */ +const enumParamDecoder: Decode.Decoder = Decode.oneOf( + checkBoxEnumParamDecoder, + selectEnumParamDecoder, + typeAheadEnumParamDecoder, + treeBoxEnumParamDecoder +); + +const parameterDecoder: Decode.Decoder = Decode.oneOf( + datasetParamDecoder, + timestampParamDecoder, + stringParamDecoder, + filterParamDecoder, + enumParamDecoder, + numberParamDecoder, + numberRangeParamDecoder, + dateParamDecoder, + dateRangeParamDecoder, + answerParamDecoder +); + +export const parametersDecoder: Decode.Decoder = + Decode.arrayOf(parameterDecoder); + +export const paramGroupDecoder: Decode.Decoder = Decode.combine( + Decode.field('description', Decode.string), + Decode.field('displayName', Decode.string), + Decode.field('displayType', Decode.string), + Decode.field('isVisible', Decode.boolean), + Decode.field('name', Decode.string), + Decode.field('parameters', Decode.arrayOf(Decode.string)) +); + +const questionSharedDecoder = Decode.combine( + Decode.combine( + Decode.field('fullName', Decode.string), + Decode.field('displayName', Decode.string), + Decode.field( + 'properties', + Decode.optional(Decode.objectOf(Decode.arrayOf(Decode.string))) + ), + Decode.field('summary', Decode.optional(Decode.string)), + Decode.field('description', Decode.optional(Decode.string)), + Decode.field('shortDisplayName', Decode.string), + Decode.field('outputRecordClassName', Decode.string), + Decode.field('help', Decode.optional(Decode.string)), + Decode.field('newBuild', Decode.optional(Decode.string)), + Decode.field('reviseBuild', Decode.optional(Decode.string)) + ), + Decode.combine( + Decode.field('urlSegment', Decode.string), + Decode.field('groups', Decode.arrayOf(paramGroupDecoder)), + Decode.field('defaultAttributes', Decode.arrayOf(Decode.string)), + Decode.field('paramNames', Decode.arrayOf(Decode.string)) + ), + Decode.field( + 'defaultSorting', + Decode.arrayOf( + Decode.combine( + Decode.field('attributeName', Decode.string), + Decode.field( + 'direction', + Decode.oneOf(Decode.constant('ASC'), Decode.constant('DESC')) + ) + ) + ) + ), + Decode.field('dynamicAttributes', Decode.arrayOf(attributeFieldDecoder)), + Decode.combine( + Decode.field('defaultSummaryView', Decode.string), + Decode.field('noSummaryOnSingleRecord', Decode.boolean), + Decode.field( + 'summaryViewPlugins', + Decode.arrayOf(summaryViewPluginFieldDecoder) + ) + ), + Decode.field('filters', Decode.arrayOf(questionFilterDecoder)), + Decode.field( + 'allowedPrimaryInputRecordClassNames', + Decode.optional(Decode.arrayOf(Decode.string)) + ), + Decode.field( + 'allowedSecondaryInputRecordClassNames', + Decode.optional(Decode.arrayOf(Decode.string)) + ), + Decode.field('isAnalyzable', Decode.boolean), + Decode.field('isCacheable', Decode.boolean) +); + +export type QuestionWithValidatedParameters = { + searchData: QuestionWithParameters; + validation: any; // FIXME: use actual type here +}; + +export const questionWithParametersDecoder: Decode.Decoder = + Decode.combine( + Decode.field( + 'searchData', + Decode.combine( + questionSharedDecoder, + Decode.field('parameters', parametersDecoder) + ) + ), + Decode.field('validation', Decode.ok) + ); + +const questionDecoder: Decode.Decoder = Decode.combine( + questionSharedDecoder, + Decode.field('parameters', Decode.arrayOf(Decode.string)) +); + +const questionsDecoder: Decode.Decoder = + Decode.arrayOf(questionDecoder); diff --git a/packages/libs/wdk-client/src/Service/Decoders/RecordClassDecoders.ts b/packages/libs/wdk-client/src/Service/Decoders/RecordClassDecoders.ts index 9121439e04..40d596ddae 100644 --- a/packages/libs/wdk-client/src/Service/Decoders/RecordClassDecoders.ts +++ b/packages/libs/wdk-client/src/Service/Decoders/RecordClassDecoders.ts @@ -23,7 +23,7 @@ export const reporterDecoder: Decode.Decoder = Decode.combine( Decode.field('name', Decode.string), Decode.field('type', Decode.string), Decode.field('displayName', Decode.string), - Decode.field('description', Decode.string), + Decode.field('description', Decode.optional(Decode.string)), Decode.field('isInReport', Decode.boolean), Decode.field('scopes', Decode.arrayOf(Decode.string)) ); diff --git a/packages/libs/wdk-client/src/Service/Mixins/SearchesService.ts b/packages/libs/wdk-client/src/Service/Mixins/SearchesService.ts index 067e32d9e8..d768d73449 100644 --- a/packages/libs/wdk-client/src/Service/Mixins/SearchesService.ts +++ b/packages/libs/wdk-client/src/Service/Mixins/SearchesService.ts @@ -2,426 +2,13 @@ import { ServiceBase } from '../../Service/ServiceBase'; import { ParameterValue, ParameterValues, - Question, QuestionWithParameters, - TreeBoxVocabNode, - Parameter, - ParameterGroup, - AttributeField, - Reporter, - SummaryViewPluginField, - DatasetParam, - TimestampParam, - StringParam, - FilterParamNew, - NumberParam, - NumberRangeParam, - DateParam, - DateRangeParam, - AnswerParam, - EnumParam, - CheckBoxEnumParam, - SinglePickCheckBoxEnumParam, - MultiPickCheckBoxEnumParam, - SinglePickSelectEnumParam, - MultiPickSelectEnumParam, - SelectEnumParam, - SinglePickTypeAheadEnumParam, - MultiPickTypeAheadEnumParam, - TypeAheadEnumParam, - SinglePickTreeBoxEnumParam, - MultiPickTreeBoxEnumParam, - TreeBoxEnumParam, } from '../../Utils/WdkModel'; import { OntologyTermSummary } from '../../Components/AttributeFilter/Types'; -import { ServiceError } from '../../Service/ServiceError'; -import * as Decode from '../../Utils/Json'; - -const reporterDecoder: Decode.Decoder = Decode.combine( - Decode.field('name', Decode.string), - Decode.field('type', Decode.string), - Decode.field('displayName', Decode.string), - Decode.field('description', Decode.string), - Decode.field('isInReport', Decode.boolean), - // TODO Replace with list of known scopes - Decode.field('scopes', Decode.arrayOf(Decode.string)) -); - -const attributeFieldDecoder: Decode.Decoder = Decode.combine( - Decode.field('name', Decode.string), - Decode.field('displayName', Decode.string), - Decode.field('formats', Decode.arrayOf(reporterDecoder)), - Decode.field( - 'properties', - Decode.optional(Decode.objectOf(Decode.arrayOf(Decode.string))) - ), - Decode.field('help', Decode.optional(Decode.string)), - Decode.field('align', Decode.optional(Decode.string)), - Decode.field('type', Decode.optional(Decode.string)), - Decode.field('truncateTo', Decode.number), - Decode.combine( - Decode.field('isSortable', Decode.boolean), - Decode.field('isRemovable', Decode.boolean), - Decode.field('isDisplayable', Decode.boolean) - ) -); - -const summaryViewPluginFieldDecoder: Decode.Decoder = - Decode.combine( - Decode.field('name', Decode.string), - Decode.field('displayName', Decode.string), - Decode.field('description', Decode.string) - ); - -const questionFilterDecoder = Decode.combine( - Decode.field('name', Decode.string), - Decode.field('displayName', Decode.optional(Decode.string)), - Decode.field('description', Decode.optional(Decode.string)), - Decode.field('isViewOnly', Decode.boolean) -); - -const paramSharedDecoder = - /* Common properties */ - Decode.combine( - Decode.combine( - Decode.field('name', Decode.string), - Decode.field('displayName', Decode.string), - Decode.field( - 'properties', - Decode.optional(Decode.objectOf(Decode.arrayOf(Decode.string))) - ), - Decode.field('help', Decode.string), - Decode.field('isVisible', Decode.boolean), - Decode.field('group', Decode.string), - Decode.field('isReadOnly', Decode.boolean), - Decode.field('initialDisplayValue', Decode.optional(Decode.string)), - Decode.field('dependentParams', Decode.arrayOf(Decode.string)) - ), - Decode.combine( - Decode.field('allowEmptyValue', Decode.boolean), - Decode.field('visibleHelp', Decode.optional(Decode.string)) - ) - ); - -/* DatasetParam */ -const datasetParamDecoder: Decode.Decoder = Decode.combine( - paramSharedDecoder, - Decode.field('type', Decode.constant('input-dataset')), - Decode.field('defaultIdList', Decode.optional(Decode.string)), - Decode.field( - 'parsers', - Decode.arrayOf( - Decode.combine( - Decode.field('name', Decode.string), - Decode.field('displayName', Decode.string), - Decode.field('description', Decode.string) - ) - ) - ) -); - -/* TimestampParam */ -const timestampParamDecoder: Decode.Decoder = Decode.combine( - paramSharedDecoder, - Decode.field('type', Decode.constant('timestamp')) -); - -/* StringParam */ -const stringParamDecoder: Decode.Decoder = Decode.combine( - paramSharedDecoder, - Decode.field('type', Decode.constant('string')), - Decode.field('length', Decode.number) -); - -/* FilterParamNew */ -const filterParamDecoder: Decode.Decoder = Decode.combine( - paramSharedDecoder, - Decode.field('type', Decode.constant('filter')), - Decode.field('filterDataTypeDisplayName', Decode.optional(Decode.string)), - Decode.field('minSelectedCount', Decode.number), - Decode.field('hideEmptyOntologyNodes', Decode.optional(Decode.boolean)), - Decode.field('values', Decode.objectOf(Decode.arrayOf(Decode.string))), - Decode.field( - 'ontology', - Decode.arrayOf( - Decode.combine( - Decode.field('term', Decode.string), - Decode.field('parent', Decode.optional(Decode.string)), - Decode.field('display', Decode.string), - Decode.field('description', Decode.optional(Decode.string)), - Decode.field( - 'type', - Decode.optional( - Decode.oneOf( - Decode.constant('date'), - Decode.constant('string'), - Decode.constant('number'), - Decode.constant('multiFilter') - ) - ) - ), - // Decode.field('units', Decode.string), - Decode.field('precision', Decode.number), - Decode.field('isRange', Decode.boolean) - ) - ) - ) -); - -/* NumberParam */ -const numberParamDecoder: Decode.Decoder = Decode.combine( - paramSharedDecoder, - Decode.field('type', Decode.constant('number')), - Decode.field('min', Decode.number), - Decode.field('max', Decode.number), - Decode.field('increment', Decode.number) -); - -/* NumberRangeParam */ -const numberRangeParamDecoder: Decode.Decoder = - Decode.combine( - paramSharedDecoder, - Decode.field('type', Decode.constant('number-range')), - Decode.field('min', Decode.number), - Decode.field('max', Decode.number), - Decode.field('increment', Decode.number) - ); - -/* DateParam */ -const dateParamDecoder: Decode.Decoder = Decode.combine( - paramSharedDecoder, - Decode.field('type', Decode.constant('date')), - Decode.field('minDate', Decode.string), - Decode.field('maxDate', Decode.string) -); - -/* DateRangeParam */ -const dateRangeParamDecoder: Decode.Decoder = Decode.combine( - paramSharedDecoder, - Decode.field('type', Decode.constant('date-range')), - Decode.field('minDate', Decode.string), - Decode.field('maxDate', Decode.string) -); - -/* AnswerParam */ -const answerParamDecoder: Decode.Decoder = Decode.combine( - paramSharedDecoder, - Decode.field('type', Decode.constant('input-step')) -); - -/* Base decoders for enum types */ -const enumParamSharedDecoder = Decode.combine( - paramSharedDecoder, - Decode.field('maxSelectedCount', Decode.number), - Decode.field('minSelectedCount', Decode.number) -); - -const singlePickEnumParamDecoder = Decode.field( - 'type', - Decode.constant('single-pick-vocabulary') -); -const multiPickEnumParamDecoder = Decode.field( - 'type', - Decode.constant('multi-pick-vocabulary') -); - -const standardVocabularyEnumParamDecoder = Decode.combine( - enumParamSharedDecoder, - Decode.field( - 'vocabulary', - Decode.arrayOf(Decode.tuple(Decode.string, Decode.string, Decode.nullValue)) - ) -); - -/* CheckBoxEnumParam */ -const checkBoxEnumParamBaseDecoder = Decode.combine( - standardVocabularyEnumParamDecoder, - Decode.field('displayType', Decode.constant('checkBox')) -); -export const singlePickCheckBoxEnumParamDecoder: Decode.Decoder = - Decode.combine(checkBoxEnumParamBaseDecoder, singlePickEnumParamDecoder); -export const multiPickCheckBoxEnumParamDecoder: Decode.Decoder = - Decode.combine(checkBoxEnumParamBaseDecoder, multiPickEnumParamDecoder); -export const checkBoxEnumParamDecoder: Decode.Decoder = - Decode.oneOf( - singlePickCheckBoxEnumParamDecoder, - multiPickCheckBoxEnumParamDecoder - ); - -/* SelectEnumParam */ -const selectEnumParamBaseDecoder = Decode.combine( - standardVocabularyEnumParamDecoder, - Decode.field('displayType', Decode.constant('select')) -); -export const singlePickSelectEnumParamDecoder: Decode.Decoder = - Decode.combine(selectEnumParamBaseDecoder, singlePickEnumParamDecoder); -export const multiPickSelectEnumParamDecoder: Decode.Decoder = - Decode.combine(selectEnumParamBaseDecoder, multiPickEnumParamDecoder); -export const selectEnumParamDecoder: Decode.Decoder = - Decode.oneOf( - singlePickSelectEnumParamDecoder, - multiPickSelectEnumParamDecoder - ); - -/* TypeAheadEnumParam */ -const typeAheadEnumParamBaseDecoder = Decode.combine( - standardVocabularyEnumParamDecoder, - Decode.field('displayType', Decode.constant('typeAhead')) -); -export const singlePickTypeAheadEnumParamDecoder: Decode.Decoder = - Decode.combine(typeAheadEnumParamBaseDecoder, singlePickEnumParamDecoder); -export const multiPickTypeAheadEnumParamDecoder: Decode.Decoder = - Decode.combine(typeAheadEnumParamBaseDecoder, multiPickEnumParamDecoder); -export const typeAheadEnumParamDecoder: Decode.Decoder = - Decode.oneOf( - singlePickTypeAheadEnumParamDecoder, - multiPickTypeAheadEnumParamDecoder - ); - -/* TreeboxEnumParam */ -const treeBoxVocabDecoder: Decode.Decoder = Decode.combine( - Decode.field( - 'data', - Decode.combine( - Decode.field('term', Decode.string), - Decode.field('display', Decode.string) - ) - ), - Decode.field( - 'children', - Decode.lazy(() => Decode.arrayOf(treeBoxVocabDecoder)) - ) -); -const treeBoxEnumParamBaseDecoder = Decode.combine( - enumParamSharedDecoder, - Decode.field('displayType', Decode.constant('treeBox')), - Decode.field('countOnlyLeaves', Decode.boolean), - Decode.field('depthExpanded', Decode.number), - Decode.field('vocabulary', treeBoxVocabDecoder) -); -export const singlePickTreeBoxEnumParamDecoder: Decode.Decoder = - Decode.combine(treeBoxEnumParamBaseDecoder, singlePickEnumParamDecoder); -export const multiPickTreeBoxEnumParamDecoder: Decode.Decoder = - Decode.combine(treeBoxEnumParamBaseDecoder, multiPickEnumParamDecoder); -export const treeBoxEnumParamDecoder: Decode.Decoder = - Decode.oneOf( - singlePickTreeBoxEnumParamDecoder, - multiPickTreeBoxEnumParamDecoder - ); - -/* EnumParam */ -const enumParamDecoder: Decode.Decoder = Decode.oneOf( - checkBoxEnumParamDecoder, - selectEnumParamDecoder, - typeAheadEnumParamDecoder, - treeBoxEnumParamDecoder -); - -const parameterDecoder: Decode.Decoder = Decode.oneOf( - datasetParamDecoder, - timestampParamDecoder, - stringParamDecoder, - filterParamDecoder, - enumParamDecoder, - numberParamDecoder, - numberRangeParamDecoder, - dateParamDecoder, - dateRangeParamDecoder, - answerParamDecoder -); - -export const parametersDecoder: Decode.Decoder = - Decode.arrayOf(parameterDecoder); - -export const paramGroupDecoder: Decode.Decoder = Decode.combine( - Decode.field('description', Decode.string), - Decode.field('displayName', Decode.string), - Decode.field('displayType', Decode.string), - Decode.field('isVisible', Decode.boolean), - Decode.field('name', Decode.string), - Decode.field('parameters', Decode.arrayOf(Decode.string)) -); - -const questionSharedDecoder = Decode.combine( - Decode.combine( - Decode.field('fullName', Decode.string), - Decode.field('displayName', Decode.string), - Decode.field( - 'properties', - Decode.optional(Decode.objectOf(Decode.arrayOf(Decode.string))) - ), - Decode.field('summary', Decode.optional(Decode.string)), - Decode.field('description', Decode.optional(Decode.string)), - Decode.field('shortDisplayName', Decode.string), - Decode.field('outputRecordClassName', Decode.string), - Decode.field('help', Decode.optional(Decode.string)), - Decode.field('newBuild', Decode.optional(Decode.string)), - Decode.field('reviseBuild', Decode.optional(Decode.string)) - ), - Decode.combine( - Decode.field('urlSegment', Decode.string), - Decode.field('groups', Decode.arrayOf(paramGroupDecoder)), - Decode.field('defaultAttributes', Decode.arrayOf(Decode.string)), - Decode.field('paramNames', Decode.arrayOf(Decode.string)) - ), - Decode.field( - 'defaultSorting', - Decode.arrayOf( - Decode.combine( - Decode.field('attributeName', Decode.string), - Decode.field( - 'direction', - Decode.oneOf(Decode.constant('ASC'), Decode.constant('DESC')) - ) - ) - ) - ), - Decode.field('dynamicAttributes', Decode.arrayOf(attributeFieldDecoder)), - Decode.combine( - Decode.field('defaultSummaryView', Decode.string), - Decode.field('noSummaryOnSingleRecord', Decode.boolean), - Decode.field( - 'summaryViewPlugins', - Decode.arrayOf(summaryViewPluginFieldDecoder) - ) - ), - Decode.field('filters', Decode.arrayOf(questionFilterDecoder)), - Decode.field( - 'allowedPrimaryInputRecordClassNames', - Decode.optional(Decode.arrayOf(Decode.string)) - ), - Decode.field( - 'allowedSecondaryInputRecordClassNames', - Decode.optional(Decode.arrayOf(Decode.string)) - ), - Decode.field('isAnalyzable', Decode.boolean), - Decode.field('isCacheable', Decode.boolean) -); - -export type QuestionWithValidatedParameters = { - searchData: QuestionWithParameters; - validation: any; // FIXME: use actual type here -}; - -const questionWithParametersDecoder: Decode.Decoder = - Decode.combine( - Decode.field( - 'searchData', - Decode.combine( - questionSharedDecoder, - Decode.field('parameters', parametersDecoder) - ) - ), - Decode.field('validation', Decode.ok) - ); - -const questionDecoder: Decode.Decoder = Decode.combine( - questionSharedDecoder, - Decode.field('parameters', Decode.arrayOf(Decode.string)) -); - -const questionsDecoder: Decode.Decoder = - Decode.arrayOf(questionDecoder); +import { + questionWithParametersDecoder, + parametersDecoder, +} from '../Decoders/QuestionDecoders'; export default (base: ServiceBase) => { async function getQuestionAndParameters( diff --git a/packages/libs/wdk-client/src/Service/Mixins/StepAnalysisService.ts b/packages/libs/wdk-client/src/Service/Mixins/StepAnalysisService.ts index 897939892e..62c50c98c4 100644 --- a/packages/libs/wdk-client/src/Service/Mixins/StepAnalysisService.ts +++ b/packages/libs/wdk-client/src/Service/Mixins/StepAnalysisService.ts @@ -12,7 +12,7 @@ import { StepAnalysisType, StepAnalysisConfig, } from '../../Utils/StepAnalysisUtils'; -import { parametersDecoder } from '../../Service/Mixins/SearchesService'; +import { parametersDecoder } from '../../Service/Decoders/QuestionDecoders'; import { Parameter, ParameterValues } from '../../Utils/WdkModel'; import { extractParamValues } from '../../Utils/WdkUser'; import { makeTraceid } from '../ServiceUtils'; diff --git a/packages/libs/wdk-client/src/Utils/StepAnalysisUtils.ts b/packages/libs/wdk-client/src/Utils/StepAnalysisUtils.ts index c224ffff58..319e34c729 100644 --- a/packages/libs/wdk-client/src/Utils/StepAnalysisUtils.ts +++ b/packages/libs/wdk-client/src/Utils/StepAnalysisUtils.ts @@ -14,7 +14,7 @@ import { string, } from './Json'; import { ParameterGroup, ParameterValues } from './WdkModel'; -import { paramGroupDecoder } from '../Service/Mixins/SearchesService'; +import { paramGroupDecoder } from '../Service/Decoders/QuestionDecoders'; import { ValidStepValidation, InvalidStepValidation } from '../Utils/WdkUser'; export interface StepAnalysis { diff --git a/packages/libs/wdk-client/src/Utils/WdkModel.ts b/packages/libs/wdk-client/src/Utils/WdkModel.ts index da7860657f..ec454e7fdb 100644 --- a/packages/libs/wdk-client/src/Utils/WdkModel.ts +++ b/packages/libs/wdk-client/src/Utils/WdkModel.ts @@ -46,7 +46,7 @@ export interface Reporter { name: string; type: string; displayName: string; - description: string; + description?: string; isInReport: boolean; scopes: string[]; } diff --git a/packages/sites/genomics-site/webapp/wdkCustomization/js/client/components/Downloads/Downloads.scss b/packages/sites/genomics-site/webapp/wdkCustomization/js/client/components/Downloads/Downloads.scss index bdb2477c50..9fba438f07 100644 --- a/packages/sites/genomics-site/webapp/wdkCustomization/js/client/components/Downloads/Downloads.scss +++ b/packages/sites/genomics-site/webapp/wdkCustomization/js/client/components/Downloads/Downloads.scss @@ -4,11 +4,15 @@ } &-Instructions { - font-size: 1.2em; - margin: 0.5em 0; + font-size: 1.1em; + margin: 1em 0 2em 0; color: #444; } + &-Instructions li { + padding-bottom: 0.3em; + } + &-Filter-Container { .wdk-QuestionFormParameterList { width: 60vw; diff --git a/packages/sites/genomics-site/webapp/wdkCustomization/js/client/components/Downloads/Downloads.tsx b/packages/sites/genomics-site/webapp/wdkCustomization/js/client/components/Downloads/Downloads.tsx index 80466313b0..a9a5fee851 100644 --- a/packages/sites/genomics-site/webapp/wdkCustomization/js/client/components/Downloads/Downloads.tsx +++ b/packages/sites/genomics-site/webapp/wdkCustomization/js/client/components/Downloads/Downloads.tsx @@ -67,8 +67,30 @@ export function Downloads() {

Download Data Files

- Use the filters to reduce the table below. Use the table to select the - files to download. +

    +
  • + Use this tool to download genome scale files such as genome.fasta or + GFF files. +
  • +
  • + All files are available in the results table below. The result can + be limited by Organism and/or Data File Properties. +
  • +
  • + To filter the result by Data File Properties, choose one or more + categories (left) and/or values (right) that define the files you + need. +
  • +
  • + Download a single file from the results table by clicking the link + in the ‘File’ column, or multiple files using the checkboxes in the + first column. +
  • +
  • + To access older files please see the{' '} + Download Archive. +
  • +

q.urlSegment === QUESTION_FOR_MAP_DATASETS ) ); - const mapStudy = useWdkService( - (wdkService) => - wdkService - .getRecord('dataset', [{ name: 'dataset_id', value: 'DS_480c976ef9' }]) - .catch(() => {}), - [] - ); - // const showInteractiveMaps = mapMenuItemsQuestion != null; - // const mapMenuItems = useMapMenuItems(mapMenuItemsQuestion); - const showInteractiveMaps = projectId === VectorBase && !!useEda; + const showInteractiveMaps = mapMenuItemsQuestion != null; + const mapMenuItems = useMapMenuItems(mapMenuItemsQuestion); // type: reactRoute, webAppRoute, externalLink, subMenu, custom const fullMenuItemEntries: HeaderMenuItemEntry[] = [ @@ -586,40 +576,56 @@ const useHeaderMenuItems = ( include: [EuPathDB, UniDB], }, }, - // { - // key: 'maps-alpha', - // display: ( - // <> - // Interactive maps BETA - // - // ), - // type: 'subMenu', - // metadata: { - // test: () => showInteractiveMaps, - // }, - // items: mapMenuItems ?? [ - // { - // key: 'maps-loading', - // type: 'custom', - // display: , - // }, - // ], - // }, - { - type: 'reactRoute', - display: ( - <> - MapVEu - {safeHtml(mapStudy?.displayName ?? '')}{' '} - BETA - - ), - key: 'map--mega-study', - url: '/workspace/maps/DS_480c976ef9/new', - target: '_blank', - metadata: { - test: () => showInteractiveMaps && mapStudy != null, - }, - }, + !showInteractiveMaps + ? { + type: 'custom', + key: 'maps-alpha', + display: null, + metadata: { + test: () => showInteractiveMaps, + }, + } + : mapMenuItems == null + ? { + key: 'maps-alpha', + type: 'custom', + display: ( + <> + MapVEu — Interactive maps{' '} + BETA{' '} + + + ), + } + : mapMenuItems.length === 1 + ? { + ...mapMenuItems[0], + display: ( + <> + MapVEu — {mapMenuItems[0].display}{' '} + BETA + + ), + } + : { + key: 'maps-alpha', + type: 'subMenu', + display: ( + <> + MapVEu — Interactive maps{' '} + BETA + + ), + items: mapMenuItems, + }, { key: 'pubcrawler', display: 'PubMed and Entrez', @@ -1196,21 +1202,21 @@ export const VEuPathDBHomePage = connect(mapStateToProps)( function useMapMenuItems(question?: Question) { const { wdkService } = useNonNullableContext(WdkDependenciesContext); - const studyAccessApi = useStudyAccessApi(); + const studyAccessApi = useStudyAccessApi_tryCatch(); const subsettingClient = useMemo( () => new SubsettingClient({ baseUrl: edaServiceUrl }, wdkService), [wdkService] ); - const [mapMenuItems, setMapMenuItems] = useState(); + const [mapMenuItems, setMapMenuItems] = useState(); useEffect(() => { - if (question == null) return; + if (question == null || studyAccessApi == null) return; getWdkStudyRecords( { studyAccessApi, subsettingClient, wdkService }, { searchName: question.urlSegment } ).then( (records) => { const menuItems = records.map( - (record): HeaderMenuItem => ({ + (record): HeaderMenuItemEntry => ({ key: `map-${record.id[0].value}`, display: record.displayName, type: 'reactRoute', @@ -1237,3 +1243,14 @@ function useMapMenuItems(question?: Question) { }, [question, studyAccessApi, subsettingClient, wdkService]); return mapMenuItems; } + +function useStudyAccessApi_tryCatch() { + // useStudyAccessApi() will throw if WdkService isn't configured for study + // access. We can ignore the error and return `undefined` to allow the + // application to handle the absence of the configuration. + try { + return useStudyAccessApi(); + } catch { + return; + } +}