UNPKG

@gooddata/gooddata-js

Version:
197 lines (168 loc) • 6.76 kB
// (C) 2007-2020 GoodData Corporation import compact from "lodash/compact"; import flatMap from "lodash/flatMap"; import get from "lodash/get"; import { AFM, VisualizationObject } from "@gooddata/typings"; import { convertVisualizationObjectExtendedFilter } from "./FilterConverter"; import MeasureConverter from "./MeasureConverter"; import { LOCATION, TOOLTIP_TEXT } from "../../DataLayer/constants/buckets"; import { IVisualizationProperties } from "./model/VisualizationObject"; function convertAttribute( attribute: VisualizationObject.IVisualizationAttribute, idx: number, ): AFM.IAttribute { const alias = attribute.visualizationAttribute.alias; const aliasProp = alias ? { alias } : {}; return { displayForm: attribute.visualizationAttribute.displayForm, localIdentifier: attribute.visualizationAttribute.localIdentifier || `a${idx + 1}`, ...aliasProp, }; } function convertAFM(visualizationObject: VisualizationObject.IVisualizationObjectContent): AFM.IAfm { const textualAttributes: AFM.IAttribute[] = getAttributes(visualizationObject.buckets).map( convertAttribute, ); const geoAttribute = getGeoAttributeForTooltip(visualizationObject); const attributes = geoAttribute ? [...textualAttributes, geoAttribute] : textualAttributes; const attrProp = attributes.length ? { attributes } : {}; const measures: AFM.IMeasure[] = getMeasures(visualizationObject.buckets).map( MeasureConverter.convertMeasure, ); const measuresProp = measures.length ? { measures } : {}; const filters: AFM.CompatibilityFilter[] = visualizationObject.filters ? compact(visualizationObject.filters.map(convertVisualizationObjectExtendedFilter)) : []; const filtersProp = filters.length ? { filters } : {}; const nativeTotals = convertNativeTotals(visualizationObject); const nativeTotalsProp = nativeTotals.length ? { nativeTotals } : {}; return { ...measuresProp, ...attrProp, ...filtersProp, ...nativeTotalsProp, }; } function getMeasures(buckets: VisualizationObject.IBucket[]): VisualizationObject.IMeasure[] { return buckets.reduce((result: VisualizationObject.IMeasure[], bucket: VisualizationObject.IBucket) => { const measureItems: VisualizationObject.IMeasure[] = bucket.items.filter( VisualizationObject.isMeasure, ); return result.concat(measureItems); }, []); } function getNativeTotalAttributeIdentifiers( bucket: VisualizationObject.IBucket, total: VisualizationObject.IVisualizationTotal, ): string[] { const attributes = bucket.items.filter(VisualizationObject.isAttribute); const totalAttributeIndex = attributes.findIndex( attribute => attribute.visualizationAttribute.localIdentifier === total.attributeIdentifier, ); return attributes .slice(0, totalAttributeIndex) .map(attribute => attribute.visualizationAttribute.localIdentifier); } function convertNativeTotals( visObj: VisualizationObject.IVisualizationObjectContent, ): AFM.INativeTotalItem[] { const nativeTotalsPerBucket = visObj.buckets.map(bucket => { const totals = bucket.totals || []; const nativeTotals = totals.filter(total => total.type === "nat"); return nativeTotals.map(total => ({ measureIdentifier: total.measureIdentifier, attributeIdentifiers: getNativeTotalAttributeIdentifiers(bucket, total), })); }); return flatMap(nativeTotalsPerBucket); } function getAttributes( buckets: VisualizationObject.IBucket[], ): VisualizationObject.IVisualizationAttribute[] { return buckets.reduce( (result: VisualizationObject.IVisualizationAttribute[], bucket: VisualizationObject.IBucket) => { const items: VisualizationObject.IVisualizationAttribute[] = bucket.items.filter( VisualizationObject.isAttribute, ); return result.concat(items); }, [], ); } function parsePropertyItem(item: string): IVisualizationProperties { try { return JSON.parse(item); } catch (e) { return {}; } } function buildTooltipBucketItem(tooltipText: string, alias: string): AFM.IAttribute { const tooltipAlias = alias ? { alias } : {}; return { localIdentifier: TOOLTIP_TEXT, displayForm: { uri: tooltipText, }, ...tooltipAlias, }; } function getGeoAttributeForTooltip( visualizationObject: VisualizationObject.IVisualizationObjectContent, ): AFM.IAttribute | null { const properties: IVisualizationProperties = parsePropertyItem(visualizationObject.properties || ""); const tooltipText: string = get(properties, "controls.tooltipText", ""); if (tooltipText) { // copy alias of Geo attribute to alias of tooltipText attribute const locationAlias: string = visualizationObject.buckets.reduce( (locationAlias: string, bucket: VisualizationObject.IBucket): string => { if (!locationAlias && bucket.localIdentifier === LOCATION) { return get(bucket, "items[0].visualizationAttribute.alias"); } return locationAlias; }, "", ); return buildTooltipBucketItem(tooltipText, locationAlias); } return null; } function convertSorting(visObj: VisualizationObject.IVisualizationObjectContent): AFM.SortItem[] { if (visObj.properties) { let properties = {}; try { properties = JSON.parse(visObj.properties); } catch { // tslint:disable-next-line:no-console console.error("Properties contains invalid JSON string."); } const sorts: AFM.SortItem[] = get(properties, "sortItems", []); return sorts ? sorts : []; } return []; } function convertResultSpec(visObj: VisualizationObject.IVisualizationObjectContent): AFM.IResultSpec { const sorts = convertSorting(visObj); // Workaround because we can handle only 1 sort item for now const sortsProp = sorts.length ? { sorts: sorts.slice(0, 1) } : {}; return { ...sortsProp, }; } export interface IConvertedAFM { afm: AFM.IAfm; resultSpec: AFM.IResultSpec; } /** * Converts visualizationObject to afm and resultSpec * * @method toAfmResultSpec * @param {VisualizationObject.IVisualizationObjectContent} visObj * @returns {IConvertedAFM} */ export function toAfmResultSpec(visObj: VisualizationObject.IVisualizationObjectContent): IConvertedAFM { const afm = convertAFM(visObj); return { afm, resultSpec: convertResultSpec(visObj), }; }