/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* eslint-disable @typescript-eslint/ban-types */ import type { ExpressionMeta } from './models'; export type OptionValue = string | number; export interface ParameterTypes { string: string; boolean: boolean; number: number; option: OptionValue; options: OptionValue[]; column: ExpressionMeta; columns: ExpressionMeta[]; aggregate: ExpressionMeta; aggregates: ExpressionMeta[]; } /** * Metadata for a parameter that may be used to render a UI control. * * Visual modules might set defaults for some of these properties, but * users of those visual modules may override them during module registration. */ export interface ControlMeta { /** * Short description of this parameter. */ label?: string; /** * Longer description of this parameter. */ description?: string; /** * Text to display when the parameter has no value. */ placeholder?: string; /** * Is this parameter required? * * This may be used by control UI elements for validation or to * determine whether to offer a "no value" option. */ required?: boolean; /** * TODO: describe me. */ transferGroup?: string; /** * Determines whether the parameter should render a control. * * If provided as a function, the function will be called with the current * set of parameter values and should return a boolean indicating whether * the control should be visible. * * If provided as a boolean, the control will always be visible or hidden. * * @default true */ visible?: boolean | ((options: { params: Record }) => boolean); } interface TypedControlMeta { option: { /** * Labels for each option. */ optionLabels?: { [key: string | number]: string }; }; options: { /** * Labels for each option. */ optionLabels?: { [key: string | number]: string }; }; string: {}; boolean: {}; number: {}; column: {}; columns: {}; aggregate: {}; aggregates: {}; } interface Droppable { add: boolean; replace: boolean; } interface TypedExtensions { number: { /** * Minimum value. */ min?: number; /** * Maximum value. */ max?: number; }; option: { /** * Possible values for this parameter. */ options: readonly OptionValue[]; }; options: { /** * Possible values for this parameter. */ options: readonly OptionValue[]; /** * Can the same option be specified multiple times? */ allowDuplicates?: boolean; }; columns: { /** * Can the same column be used multiple times? */ allowDuplicates?: boolean; /** * Can we drop stuff for this? */ droppable?: Droppable; }; string: {}; boolean: {}; column: { droppable?: Droppable; }; aggregate: { droppable?: Droppable; }; aggregates: { droppable?: Droppable; }; } export type TypedParameter = TypedExtensions[Type] & { /** * Parameter type. */ type: Type; /** * Default value for this parameter. */ default?: ParameterTypes[Type]; /** * Metadata for rendering a UI control for this parameter. */ control?: ControlMeta & TypedControlMeta[Type]; /** * Validate the value of this parameter. * * @param value - Current parameter value or undefined if no value has been set. * @returns - An error message if the value is invalid, or undefined if the value is valid. */ validate?: (value: ParameterTypes[Type] | undefined) => string | undefined; /** * Determines whether the parameter should exist in the visual modules parameters. * * If the provided function returns false, the parameter value will be deleted from * the module's parameters. If true, it will be whatever the relative control * * @default undefined */ defined?: (options: { parametersValues: Record }) => boolean; }; /** * A dynamic input to a visual module that may affect its query or rendering. */ export type Parameter = | TypedParameter<'string'> | TypedParameter<'boolean'> | TypedParameter<'number'> | TypedParameter<'option'> | TypedParameter<'options'> | TypedParameter<'column'> | TypedParameter<'columns'> | TypedParameter<'aggregate'> | TypedParameter<'aggregates'>; export type NoParams = Record; export type ParameterDefinitions = Record; export function getPluginOptionLabel(o: OptionValue, parameter: Parameter): string { if (parameter.type !== 'option' && parameter.type !== 'options') { return 'Not an option parameter'; } const { optionLabels } = parameter.control ?? {}; return ( optionLabels?.[o] ?? (typeof o === 'string' ? o : typeof o !== 'undefined' ? String(o) : 'Malformed option') ); } export type DroppableParameter = | ( | TypedParameter<'column'> | TypedParameter<'columns'> | TypedParameter<'aggregate'> | TypedParameter<'aggregates'> ) & { droppable: Droppable }; export function isParameterPossiblyDroppable( parameter: Parameter, draggedType: 'dimension' | 'measure' | 'compare', ): parameter is DroppableParameter { return ( (draggedType === 'dimension' && (parameter.type === 'column' || parameter.type === 'columns')) || (draggedType === 'measure' && (parameter.type === 'aggregate' || parameter.type === 'aggregates')) ); }