diff --git a/src/client/visualizations/scatterplot/point.tsx b/src/client/visualizations/scatterplot/point.tsx
index 94bb0bb3c..5f929adf0 100644
--- a/src/client/visualizations/scatterplot/point.tsx
+++ b/src/client/visualizations/scatterplot/point.tsx
@@ -19,7 +19,9 @@ import { Datum } from "plywood";
import { ConcreteSeries } from "../../../common/models/series/concrete-series";
import "./scatterplot.scss";
+import { lightMain } from "../../../common/models/colors/colors";
import { LinearScale } from "../../utils/linear-scale/linear-scale";
+import { useSettingsContext } from "../../views/cube-view/settings-context";
interface PointProps {
datum: Datum;
@@ -35,9 +37,13 @@ const POINT_RADIUS = 3;
const HOVER_AREA_RADIUS = 6;
export const Point: React.FunctionComponent = ({ datum, xScale, yScale, xSeries, ySeries, setHover, resetHover }) => {
+ const { customization: { visualizationColors } } = useSettingsContext();
const xValue = xSeries.selectValue(datum);
const yValue = ySeries.selectValue(datum);
+ const stroke = visualizationColors.main;
+ const fill = lightMain(visualizationColors);
+
return (
<>
= ({ datum, xScale, ySca
cy={yScale(yValue)}
r={POINT_RADIUS}
className="point"
+ stroke={stroke}
+ fill={fill}
/>
setHover(datum)}
diff --git a/src/client/visualizations/scatterplot/scatterplot.scss b/src/client/visualizations/scatterplot/scatterplot.scss
index 576c943ee..4fa0288e5 100644
--- a/src/client/visualizations/scatterplot/scatterplot.scss
+++ b/src/client/visualizations/scatterplot/scatterplot.scss
@@ -47,11 +47,6 @@
}
}
- .point {
- @include css-variable(stroke, brand);
- @include css-variable(fill, item-dimension);
- }
-
.axis-title {
position: absolute;
font-weight: $bold;
diff --git a/src/common/models/app-settings/app-settings.fixtures.ts b/src/common/models/app-settings/app-settings.fixtures.ts
index 950bd1561..81d3f8b44 100644
--- a/src/common/models/app-settings/app-settings.fixtures.ts
+++ b/src/common/models/app-settings/app-settings.fixtures.ts
@@ -15,6 +15,7 @@
* limitations under the License.
*/
+import { DEFAULT_COLORS } from "../colors/colors";
import { LOCALES } from "../locale/locale";
import { AppSettings, ClientAppSettings } from "./app-settings";
@@ -25,7 +26,8 @@ export const clientAppSettings: ClientAppSettings = {
externalViews: [],
timezones: [],
locale: LOCALES["en-US"],
- messages: {}
+ messages: {},
+ visualizationColors: DEFAULT_COLORS
},
oauth: { status: "disabled" },
clientTimeout: 1000
@@ -38,7 +40,8 @@ export const appSettings: AppSettings = {
locale: LOCALES["en-US"],
externalViews: [],
cssVariables: {},
- messages: {}
+ messages: {},
+ visualizationColors: DEFAULT_COLORS
},
oauth: { status: "disabled" },
version: 0
diff --git a/src/common/models/colors/colors.ts b/src/common/models/colors/colors.ts
index e4d2ded48..cbb747c88 100644
--- a/src/common/models/colors/colors.ts
+++ b/src/common/models/colors/colors.ts
@@ -15,7 +15,9 @@
* limitations under the License.
*/
-export const NORMAL_COLORS = [
+import { hsl, rgb } from "d3";
+
+export const DEFAULT_SERIES_COLORS = [
"#2D95CA",
"#EFB925",
"#DA4E99",
@@ -27,3 +29,24 @@ export const NORMAL_COLORS = [
"#B0B510",
"#904064"
];
+
+export const DEFAULT_MAIN_COLOR = "#FF5900";
+
+export const DEFAULT_COLORS: VisualizationColors = {
+ main: DEFAULT_MAIN_COLOR,
+ series: DEFAULT_SERIES_COLORS
+};
+
+export interface VisualizationColors {
+ main: string;
+ series: string[];
+}
+
+export function lightMain(colors: VisualizationColors): string {
+ return hsl(colors.main).brighter(1.3).toString();
+}
+
+export function alphaMain(colors: VisualizationColors): string {
+ const { r, g, b } = rgb(colors.main);
+ return `rgba(${r}, ${g}, ${b}, ${0.14})`;
+}
diff --git a/src/common/models/customization/customization.fixtures.ts b/src/common/models/customization/customization.fixtures.ts
index 285e7e61d..0a94b2ec2 100644
--- a/src/common/models/customization/customization.fixtures.ts
+++ b/src/common/models/customization/customization.fixtures.ts
@@ -14,10 +14,15 @@
* limitations under the License.
*/
+import { DEFAULT_COLORS } from "../colors/colors";
import { UrlShortenerContext } from "../url-shortener/url-shortener";
import { Customization, CustomizationJS } from "./customization";
export const customization: Customization = {
+ messages: {
+ dataCubeNotFound: "404: Data Cube Not Found"
+ },
+ visualizationColors: DEFAULT_COLORS,
cssVariables: {
"brand-selected": "orange",
"brand": "red",
diff --git a/src/common/models/customization/customization.mocha.ts b/src/common/models/customization/customization.mocha.ts
index fad05f634..e0754d9bc 100644
--- a/src/common/models/customization/customization.mocha.ts
+++ b/src/common/models/customization/customization.mocha.ts
@@ -18,6 +18,7 @@
import { expect } from "chai";
import { Timezone } from "chronoshift";
import * as sinon from "sinon";
+import { DEFAULT_COLORS, DEFAULT_MAIN_COLOR, DEFAULT_SERIES_COLORS } from "../colors/colors";
import * as localeModule from "../locale/locale";
import * as urlShortenerModule from "../url-shortener/url-shortener";
import { Customization, DEFAULT_TIMEZONES, DEFAULT_TITLE, fromConfig, serialize } from "./customization";
@@ -161,6 +162,44 @@ describe("Customization", () => {
});
});
});
+
+ describe("visualizationColors", () => {
+ it("should set default colors if no colors are defined", () => {
+ const customization = fromConfig({ ...customizationJS, visualizationColors: undefined });
+
+ expect(customization).to.deep.contain({ visualizationColors: DEFAULT_COLORS });
+ });
+
+ it("should override default main color when property is defined", () => {
+ const customization = fromConfig({
+ ...customizationJS, visualizationColors: {
+ main: "foobar-color"
+ }
+ });
+
+ expect(customization).to.deep.contain({
+ visualizationColors: {
+ series: DEFAULT_SERIES_COLORS,
+ main: "foobar-color"
+ }
+ });
+ });
+
+ it("should override default series colors when property is defined", () => {
+ const customization = fromConfig({
+ ...customizationJS, visualizationColors: {
+ series: ["one fish", "two fish", "red fish", "blue fish"]
+ }
+ });
+
+ expect(customization).to.deep.contain({
+ visualizationColors: {
+ series: ["one fish", "two fish", "red fish", "blue fish"],
+ main: DEFAULT_MAIN_COLOR
+ }
+ });
+ });
+ });
});
describe("serialize", () => {
@@ -203,6 +242,16 @@ describe("Customization", () => {
expect(serialized).to.deep.contain({ timezones: ["Europe/Warsaw", "Asia/Manila"] });
});
+ it("should pass visualizationColors as is", () => {
+ const colors = { main: "fake-color", series: ["one series color"] };
+ const serialized = serialize({
+ ...customization,
+ visualizationColors: colors
+ });
+
+ expect(serialized).to.deep.contain({ visualizationColors: colors });
+ });
+
describe("externalViews", () => {
// TODO: Implement
});
@@ -212,7 +261,8 @@ describe("Customization", () => {
it("should return hasUrlShortener true if has url shortener", () => {
const serialized = serialize({
...customization,
- urlShortener: (() => {}) as any
+ urlShortener: (() => {
+ }) as any
});
expect(serialized).to.contain({ hasUrlShortener: true });
diff --git a/src/common/models/customization/customization.ts b/src/common/models/customization/customization.ts
index 1e9092399..22b743058 100644
--- a/src/common/models/customization/customization.ts
+++ b/src/common/models/customization/customization.ts
@@ -18,7 +18,8 @@
import { Timezone } from "chronoshift";
import { LOGGER } from "../../logger/logger";
import { assoc } from "../../utils/functional/functional";
-import { isTruthy } from "../../utils/general/general";
+import { isNil, isTruthy } from "../../utils/general/general";
+import { DEFAULT_COLORS, DEFAULT_MAIN_COLOR, DEFAULT_SERIES_COLORS, VisualizationColors } from "../colors/colors";
import { ExternalView, ExternalViewValue } from "../external-view/external-view";
import { fromConfig as localeFromConfig, Locale, LocaleJS, serialize as serializeLocale } from "../locale/locale";
import { fromConfig as urlShortenerFromConfig, UrlShortener, UrlShortenerDef } from "../url-shortener/url-shortener";
@@ -87,8 +88,6 @@ const availableCssVariables = [
"item-measure-hover",
"item-measure-text",
"item-measure",
- "main-time-area",
- "main-time-line",
"negative",
"pinboard-icon",
"positive",
@@ -120,6 +119,7 @@ export interface Customization {
cssVariables: CssVariables;
locale: Locale;
messages: Messages;
+ visualizationColors: VisualizationColors;
}
export interface CustomizationJS {
@@ -133,6 +133,7 @@ export interface CustomizationJS {
sentryDSN?: string;
cssVariables?: Record;
messages?: Messages;
+ visualizationColors?: Partial;
}
export interface SerializedCustomization {
@@ -144,6 +145,7 @@ export interface SerializedCustomization {
sentryDSN?: string;
locale: Locale;
messages: Messages;
+ visualizationColors: VisualizationColors;
}
export interface ClientCustomization {
@@ -155,6 +157,7 @@ export interface ClientCustomization {
sentryDSN?: string;
locale: Locale;
messages: Messages;
+ visualizationColors: VisualizationColors;
}
function verifyCssVariables(cssVariables: Record): CssVariables {
@@ -171,6 +174,12 @@ function verifyCssVariables(cssVariables: Record): CssVariables
}, {});
}
+function readVisualizationColors(config: CustomizationJS): VisualizationColors {
+ if (isNil(config.visualizationColors)) return DEFAULT_COLORS;
+
+ return { ...DEFAULT_COLORS, ...config.visualizationColors };
+}
+
export function fromConfig(config: CustomizationJS = {}): Customization {
const {
title = DEFAULT_TITLE,
@@ -193,6 +202,8 @@ export function fromConfig(config: CustomizationJS = {}): Customization {
? configExternalViews.map(ExternalView.fromJS)
: [];
+ const visualizationColors = readVisualizationColors(config);
+
return {
title,
headerBackground,
@@ -203,12 +214,13 @@ export function fromConfig(config: CustomizationJS = {}): Customization {
timezones,
locale: localeFromConfig(locale),
messages,
- externalViews
+ externalViews,
+ visualizationColors
};
}
export function serialize(customization: Customization): SerializedCustomization {
- const { customLogoSvg, timezones, headerBackground, locale, externalViews, sentryDSN, urlShortener, messages } = customization;
+ const { customLogoSvg, timezones, headerBackground, locale, externalViews, sentryDSN, urlShortener, messages, visualizationColors } = customization;
return {
customLogoSvg,
externalViews,
@@ -217,7 +229,8 @@ export function serialize(customization: Customization): SerializedCustomization
sentryDSN,
locale: serializeLocale(locale),
timezones: timezones.map(t => t.toJS()),
- messages
+ messages,
+ visualizationColors
};
}
diff --git a/src/common/models/essence/essence.fixtures.ts b/src/common/models/essence/essence.fixtures.ts
index 93c5983a7..5efe27b65 100644
--- a/src/common/models/essence/essence.fixtures.ts
+++ b/src/common/models/essence/essence.fixtures.ts
@@ -21,9 +21,23 @@ import { HEAT_MAP_MANIFEST } from "../../visualization-manifests/heat-map/heat-m
import { LINE_CHART_MANIFEST } from "../../visualization-manifests/line-chart/line-chart";
import { TABLE_MANIFEST } from "../../visualization-manifests/table/table";
import { TOTALS_MANIFEST } from "../../visualization-manifests/totals/totals";
+import { clientAppSettings } from "../app-settings/app-settings.fixtures";
import { customClientCube, twitterClientDataCube, wikiClientDataCube } from "../data-cube/data-cube.fixtures";
-import { NumberFilterClause, NumberRange, RelativeTimeFilterClause, TimeFilterPeriod } from "../filter-clause/filter-clause";
-import { boolean, numberRange, stringContains, stringIn, stringMatch, timePeriod, timeRange } from "../filter-clause/filter-clause.fixtures";
+import {
+ NumberFilterClause,
+ NumberRange,
+ RelativeTimeFilterClause,
+ TimeFilterPeriod
+} from "../filter-clause/filter-clause";
+import {
+ boolean,
+ numberRange,
+ stringContains,
+ stringIn,
+ stringMatch,
+ timePeriod,
+ timeRange
+} from "../filter-clause/filter-clause.fixtures";
import { Filter } from "../filter/filter";
import { EMPTY_SERIES, SeriesList } from "../series-list/series-list";
import { measureSeries } from "../series/series.fixtures";
@@ -35,6 +49,7 @@ import { VisualizationManifest } from "../visualization-manifest/visualization-m
import { Essence, EssenceValue, VisStrategy } from "./essence";
const defaultEssence: EssenceValue = {
+ appSettings: clientAppSettings,
dataCube: customClientCube("essence-fixture-data-cube", "essence-fixture-data-cube"),
visualization: null,
visualizationSettings: null,
@@ -96,6 +111,7 @@ export class EssenceFixtures {
stringSplitCombine("namespace", { sort: { reference: "added", direction: SortDirection.descending }, limit: 5 })
];
return new Essence({
+ appSettings: clientAppSettings,
dataCube: wikiClientDataCube,
visualization: HEAT_MAP_MANIFEST,
visualizationSettings: HEAT_MAP_MANIFEST.visualizationSettings.defaults,
@@ -130,6 +146,7 @@ export class EssenceFixtures {
measureSeries("added")
];
return new Essence({
+ appSettings: clientAppSettings,
dataCube: wikiClientDataCube,
visualization: TABLE_MANIFEST as unknown as VisualizationManifest,
visualizationSettings: TABLE_MANIFEST.visualizationSettings.defaults,
@@ -158,6 +175,7 @@ export class EssenceFixtures {
measureSeries("added")
];
return new Essence({
+ appSettings: clientAppSettings,
dataCube: wikiClientDataCube,
visualization: LINE_CHART_MANIFEST as unknown as VisualizationManifest,
visualizationSettings: LINE_CHART_MANIFEST.visualizationSettings.defaults,
diff --git a/src/common/models/essence/essence.mocha.ts b/src/common/models/essence/essence.mocha.ts
index c191a7b38..3a33b7ff2 100644
--- a/src/common/models/essence/essence.mocha.ts
+++ b/src/common/models/essence/essence.mocha.ts
@@ -22,6 +22,7 @@ import { GRID_MANIFEST } from "../../visualization-manifests/grid/grid";
import { LINE_CHART_MANIFEST } from "../../visualization-manifests/line-chart/line-chart";
import { TABLE_MANIFEST } from "../../visualization-manifests/table/table";
import { TOTALS_MANIFEST } from "../../visualization-manifests/totals/totals";
+import { clientAppSettings } from "../app-settings/app-settings.fixtures";
import { twitterClientDataCube } from "../data-cube/data-cube.fixtures";
import { TimeFilterPeriod } from "../filter-clause/filter-clause";
import { timePeriod } from "../filter-clause/filter-clause.fixtures";
@@ -33,6 +34,7 @@ import { DimensionSort, SortDirection } from "../sort/sort";
import { Split, SplitType } from "../split/split";
import { Splits } from "../splits/splits";
import { TimeShift } from "../time-shift/time-shift";
+import { VisualizationManifest } from "../visualization-manifest/visualization-manifest";
import { Essence, VisStrategy } from "./essence";
import { EssenceFixtures } from "./essence.fixtures";
@@ -41,7 +43,7 @@ describe("EssenceProps", () => {
describe(".fromDataCube", () => {
it.skip("works in the base case", () => {
- const essence = Essence.fromDataCube(dataCube);
+ const essence = Essence.fromDataCube(dataCube, clientAppSettings);
// TODO: don't test toJS
expect(essence.toJS()).to.deep.equal({
@@ -135,7 +137,7 @@ describe("EssenceProps", () => {
sort: new DimensionSort({ reference: "time", direction: SortDirection.ascending })
})],
series,
- current: null,
+ current: null as VisualizationManifest,
expected: LINE_CHART_MANIFEST
}
];
@@ -143,6 +145,7 @@ describe("EssenceProps", () => {
tests.forEach(({ splits, current, series, expected }) => {
it(`chooses ${expected.name} given splits: [${splits}] with current ${current && current.name}`, () => {
const { visualization } = Essence.getBestVisualization(
+ clientAppSettings,
twitterClientDataCube,
Splits.fromSplits(splits),
SeriesList.fromSeries(series),
@@ -269,7 +272,7 @@ describe("EssenceProps", () => {
describe("#changeVisualisation", () => {
[TABLE_MANIFEST, LINE_CHART_MANIFEST, BAR_CHART_MANIFEST].forEach(manifest => {
it("it sets visResolve to manual", () => {
- const essence = EssenceFixtures.twitterNoVisualisation().changeVisualization(manifest);
+ const essence = EssenceFixtures.twitterNoVisualisation().changeVisualization(manifest as VisualizationManifest);
expect(essence.visualization.name).to.deep.equal(manifest.name);
expect(essence.visResolve.isManual()).to.be.true;
});
diff --git a/src/common/models/essence/essence.ts b/src/common/models/essence/essence.ts
index acd173ebb..c07ddb0ba 100644
--- a/src/common/models/essence/essence.ts
+++ b/src/common/models/essence/essence.ts
@@ -17,11 +17,13 @@
import { Timezone } from "chronoshift";
import { List, OrderedSet, Record as ImmutableRecord, Set } from "immutable";
-import { serialize } from "../../../client/deserializers/data-cube";
+import { serialize as serializeAppSettings } from "../../../client/deserializers/app-settings";
+import { serialize as serializeDataCube } from "../../../client/deserializers/data-cube";
import { thread } from "../../utils/functional/functional";
import nullableEquals from "../../utils/immutable-utils/nullable-equals";
import { visualizationIndependentEvaluator } from "../../utils/rules/visualization-independent-evaluator";
import { MANIFESTS } from "../../visualization-manifests";
+import { ClientAppSettings } from "../app-settings/app-settings";
import {
ClientDataCube,
getDefaultFilter,
@@ -78,6 +80,7 @@ export enum VisStrategy {
type DimensionId = string;
export interface EssenceValue {
+ appSettings: ClientAppSettings;
dataCube: ClientDataCube;
visualization: VisualizationManifest;
visualizationSettings: VisualizationSettings | null;
@@ -92,6 +95,7 @@ export interface EssenceValue {
}
const defaultEssence: EssenceValue = {
+ appSettings: null,
dataCube: null,
visualization: null,
visualizationSettings: null,
@@ -111,18 +115,18 @@ export interface EffectiveFilterOptions {
}
type VisualizationResolverResult = Pick;
-type VisualizationResolverParameters = Pick;
+type VisualizationResolverParameters = Pick;
-function resolveVisualization({ visualization, dataCube, splits, series }: VisualizationResolverParameters): VisualizationResolverResult {
+function resolveVisualization({ visualization, dataCube, splits, series, appSettings }: VisualizationResolverParameters): VisualizationResolverResult {
let visResolve: Resolve;
// Place vis here because it needs to know about splits and colors (and maybe later other things)
if (!visualization) {
- const visAndResolve = Essence.getBestVisualization(dataCube, splits, series, null);
+ const visAndResolve = Essence.getBestVisualization(appSettings, dataCube, splits, series, null);
visualization = visAndResolve.visualization;
}
- const ruleVariables = { dataCube, series, splits, isSelectedVisualization: true };
+ const ruleVariables = { appSettings, dataCube, series, splits, isSelectedVisualization: true };
visResolve = visualization.evaluateRules(ruleVariables);
if (visResolve.isAutomatic()) {
const adjustment = visResolve.adjustment;
@@ -143,6 +147,7 @@ function resolveVisualization({ visualization, dataCube, splits, series }: Visua
export class Essence extends ImmutableRecord(defaultEssence) {
static getBestVisualization(
+ appSettings: ClientAppSettings,
dataCube: ClientDataCube,
splits: Splits,
series: SeriesList,
@@ -150,7 +155,7 @@ export class Essence extends ImmutableRecord(defaultEssence) {
): VisualizationAndResolve {
const visAndResolves = MANIFESTS.map(visualization => {
const isSelectedVisualization = visualization === currentVisualization;
- const ruleVariables = { dataCube, splits, series, isSelectedVisualization };
+ const ruleVariables = { appSettings, dataCube, splits, series, isSelectedVisualization };
return {
visualization,
resolve: visualization.evaluateRules(ruleVariables)
@@ -160,8 +165,9 @@ export class Essence extends ImmutableRecord(defaultEssence) {
return visAndResolves.sort((vr1, vr2) => Resolve.compare(vr1.resolve, vr2.resolve))[0];
}
- static fromDataCube(dataCube: ClientDataCube): Essence {
+ static fromDataCube(dataCube: ClientDataCube, appSettings: ClientAppSettings): Essence {
const essence = new Essence({
+ appSettings,
dataCube,
visualization: null,
visualizationSettings: null,
@@ -238,9 +244,10 @@ export class Essence extends ImmutableRecord(defaultEssence) {
public toJS() {
return {
+ appSettings: serializeAppSettings(this.appSettings),
visualization: this.visualization,
visualizationSettings: this.visualizationSettings,
- dataCube: serialize(this.dataCube),
+ dataCube: serializeDataCube(this.dataCube),
timezone: this.timezone.toJS(),
filter: this.filter && this.filter.toJS(),
splits: this.splits && this.splits.toJS(),
@@ -435,9 +442,9 @@ export class Essence extends ImmutableRecord(defaultEssence) {
}
function adjustVisualization(essence: Essence): Essence {
- const { dataCube, visualization, splits, series } = essence;
+ const { dataCube, visualization, splits, series, appSettings } = essence;
const { visualization: newVis } = Essence.getBestVisualization(
- dataCube, splits, series, visualization);
+ appSettings, dataCube, splits, series, visualization);
if (newVis === visualization) return essence;
return essence.changeVisualization(newVis, newVis.visualizationSettings.defaults);
}
@@ -501,7 +508,7 @@ export class Essence extends ImmutableRecord(defaultEssence) {
}
public changeSplits(splits: Splits, strategy: VisStrategy): Essence {
- const { splits: oldSplits, dataCube, visualization, visResolve, filter, series } = this;
+ const { splits: oldSplits, appSettings, dataCube, visualization, visResolve, filter, series } = this;
const newSplits = this.setSortOnSplits(splits).updateWithFilter(filter, dataCube.dimensions);
@@ -518,7 +525,7 @@ export class Essence extends ImmutableRecord(defaultEssence) {
function adjustVisualization(essence: Essence): Essence {
if (adjustStrategy(strategy) !== VisStrategy.FairGame) return essence;
- const { visualization: newVis } = Essence.getBestVisualization(dataCube, newSplits, series, visualization);
+ const { visualization: newVis } = Essence.getBestVisualization(appSettings, dataCube, newSplits, series, visualization);
if (newVis === visualization) return essence;
return essence.changeVisualization(newVis, newVis.visualizationSettings.defaults);
}
@@ -611,9 +618,10 @@ export class Essence extends ImmutableRecord(defaultEssence) {
.resolveVisualizationAndUpdate();
}
+ // NOTE: Pass appsettings to all callers. Probably all callers are from Clicker object
public resolveVisualizationAndUpdate() {
- const { visualization, splits, dataCube, series } = this;
- const result = resolveVisualization({ splits, dataCube, visualization, series });
+ const { visualization, splits, dataCube, series, appSettings } = this;
+ const result = resolveVisualization({ appSettings, dataCube, visualization, splits, series });
return this
.set("visResolve", result.visResolve)
.set("visualization", result.visualization)
diff --git a/src/common/utils/rules/split-adjustments.mocha.ts b/src/common/utils/rules/split-adjustments.mocha.ts
index 9fcd2d55e..e34da7286 100644
--- a/src/common/utils/rules/split-adjustments.mocha.ts
+++ b/src/common/utils/rules/split-adjustments.mocha.ts
@@ -16,6 +16,7 @@
import { expect } from "chai";
import { $ } from "plywood";
+import { DEFAULT_COLORS } from "../../models/colors/colors";
import { createDimension, Dimension } from "../../models/dimension/dimension";
import { SeriesList } from "../../models/series-list/series-list";
import { measureSeries } from "../../models/series/series.fixtures";
@@ -118,7 +119,7 @@ describe("Split adjustment utilities", () => {
limits: [42, 100]
};
const split = stringSplitCombine("foobar", { limit: 50 });
- const adjusted = adjustColorSplit(split, dimension, SeriesList.fromSeries([]));
+ const adjusted = adjustColorSplit(split, dimension, SeriesList.fromSeries([]), DEFAULT_COLORS);
expect(adjusted.limit).to.be.equal(10);
});
diff --git a/src/common/utils/rules/split-adjustments.ts b/src/common/utils/rules/split-adjustments.ts
index fb8d5583e..06a43100f 100644
--- a/src/common/utils/rules/split-adjustments.ts
+++ b/src/common/utils/rules/split-adjustments.ts
@@ -14,21 +14,20 @@
* limitations under the License.
*/
-import { NORMAL_COLORS } from "../../models/colors/colors";
+import { VisualizationColors } from "../../models/colors/colors";
import { Dimension } from "../../models/dimension/dimension";
import { SeriesList } from "../../models/series-list/series-list";
import { DimensionSort, SeriesSort, SortDirection } from "../../models/sort/sort";
import { Split, SplitType } from "../../models/split/split";
import { thread } from "../functional/functional";
-const COLORS_COUNT = NORMAL_COLORS.length;
-
-export function adjustColorSplit(split: Split, dimension: Dimension, series: SeriesList): Split {
+export function adjustColorSplit(split: Split, dimension: Dimension, series: SeriesList, visualizationColors: VisualizationColors): Split {
+ const colorsCount = visualizationColors.series.length;
return thread(
split,
adjustSort(dimension, series),
// TODO: This magic 5 will disappear in #756
- adjustFiniteLimit([5, COLORS_COUNT], COLORS_COUNT)
+ adjustFiniteLimit([5, colorsCount], colorsCount)
);
}
diff --git a/src/common/utils/rules/visualization-dependent-evaluator.ts b/src/common/utils/rules/visualization-dependent-evaluator.ts
index 648e468c1..dbf4003ca 100644
--- a/src/common/utils/rules/visualization-dependent-evaluator.ts
+++ b/src/common/utils/rules/visualization-dependent-evaluator.ts
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+import { ClientAppSettings } from "../../models/app-settings/app-settings";
import { ClientDataCube } from "../../models/data-cube/data-cube";
import { SeriesList } from "../../models/series-list/series-list";
import { Splits } from "../../models/splits/splits";
@@ -27,6 +28,7 @@ export interface PredicateVariables {
}
export interface ActionVariables {
+ appSettings: ClientAppSettings;
dataCube: ClientDataCube;
splits: Splits;
series: SeriesList;
diff --git a/src/common/utils/url-hash-converter/url-hash-converter.mocha.ts b/src/common/utils/url-hash-converter/url-hash-converter.mocha.ts
index 5edf3f25e..35f8a8d53 100644
--- a/src/common/utils/url-hash-converter/url-hash-converter.mocha.ts
+++ b/src/common/utils/url-hash-converter/url-hash-converter.mocha.ts
@@ -15,6 +15,7 @@
*/
import { expect } from "chai";
+import { clientAppSettings } from "../../models/app-settings/app-settings.fixtures";
import { wikiClientDataCube } from "../../models/data-cube/data-cube.fixtures";
import { Essence } from "../../models/essence/essence";
import { EssenceFixtures } from "../../models/essence/essence.fixtures";
@@ -41,7 +42,7 @@ describe("urlHashConverter", () => {
const { visualization } = essence;
it(`decodes ${visualization.name} version ${version} correctly`, () => {
- const decodedEssence = urlHashConverter.essenceFromHash(hash, wikiClientDataCube);
+ const decodedEssence = urlHashConverter.essenceFromHash(hash, clientAppSettings, wikiClientDataCube);
expect(decodedEssence.toJS()).to.deep.equal(essence.toJS());
});
@@ -58,7 +59,7 @@ describe("urlHashConverter", () => {
const { visualization } = essence;
it(`decodes ${visualization.name} version ${version} correctly`, () => {
- const decodedEssence = urlHashConverter.essenceFromHash(hash, wikiClientDataCube);
+ const decodedEssence = urlHashConverter.essenceFromHash(hash, clientAppSettings, wikiClientDataCube);
expect(decodedEssence.toJS()).to.deep.equal(essence.toJS());
});
@@ -75,14 +76,14 @@ describe("urlHashConverter", () => {
const { visualization } = essence;
it(`decodes ${visualization.name} version ${version} correctly`, () => {
- const decodedEssence = urlHashConverter.essenceFromHash(hash, wikiClientDataCube);
+ const decodedEssence = urlHashConverter.essenceFromHash(hash, clientAppSettings, wikiClientDataCube);
expect(decodedEssence.toJS()).to.deep.equal(essence.toJS());
});
it(`is symmetric in decode/encode for ${visualization.name} in version ${version}`, () => {
const encodedHash = urlHashConverter.toHash(essence, version);
- const decodedEssence = urlHashConverter.essenceFromHash(encodedHash, wikiClientDataCube);
+ const decodedEssence = urlHashConverter.essenceFromHash(encodedHash, clientAppSettings, wikiClientDataCube);
expect(essence.toJS()).to.deep.equal(decodedEssence.toJS());
});
@@ -93,7 +94,7 @@ describe("urlHashConverter", () => {
}
it(`is symmetric in encode/decode for ${visualization.name} in version ${version}`, () => {
- const decodedEssence = urlHashConverter.essenceFromHash(hash, wikiClientDataCube);
+ const decodedEssence = urlHashConverter.essenceFromHash(hash, clientAppSettings, wikiClientDataCube);
const encodedHash = urlHashConverter.toHash(decodedEssence, version);
try {
@@ -115,7 +116,7 @@ describe("urlHashConverter", () => {
minimalNumberOfSegmentsTests.forEach(({ version, hash }) => {
it(`decodes version ${version} with minimal number of segments`, () => {
- const decodedEssence = urlHashConverter.essenceFromHash(hash, wikiClientDataCube);
+ const decodedEssence = urlHashConverter.essenceFromHash(hash, clientAppSettings, wikiClientDataCube);
expect(decodedEssence).to.be.an.instanceOf(Essence);
});
@@ -130,7 +131,7 @@ describe("urlHashConverter", () => {
wrongHashStructureTests.forEach(({ hash, errorMessage }) => {
it(`throws error for hash: "${hash}" with wrong structure`, () => {
- const essenceFromHashCall = () => urlHashConverter.essenceFromHash(hash, wikiClientDataCube);
+ const essenceFromHashCall = () => urlHashConverter.essenceFromHash(hash, clientAppSettings, wikiClientDataCube);
expect(essenceFromHashCall).to.throw(errorMessage);
});
});
diff --git a/src/common/utils/url-hash-converter/url-hash-converter.ts b/src/common/utils/url-hash-converter/url-hash-converter.ts
index c068eadef..5cc6e0aee 100644
--- a/src/common/utils/url-hash-converter/url-hash-converter.ts
+++ b/src/common/utils/url-hash-converter/url-hash-converter.ts
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+import { ClientAppSettings } from "../../models/app-settings/app-settings";
import { ClientDataCube } from "../../models/data-cube/data-cube";
import { Essence } from "../../models/essence/essence";
import { Visualization } from "../../models/visualization-manifest/visualization-manifest";
@@ -30,7 +31,7 @@ const SEGMENT_SEPARATOR = "/";
const MINIMAL_HASH_SEGMENTS_COUNT = 2;
export interface UrlHashConverter {
- essenceFromHash(hash: string, dataCube: ClientDataCube): Essence;
+ essenceFromHash(hash: string, appSettings: ClientAppSettings, dataCube: ClientDataCube): Essence;
toHash(essence: Essence, version?: ViewDefinitionVersion): string;
}
@@ -85,14 +86,14 @@ export function getHashSegments(hash: string): HashSegments {
}
export const urlHashConverter: UrlHashConverter = {
- essenceFromHash(hash: string, dataCube: ClientDataCube): Essence {
+ essenceFromHash(hash: string, appSettings: ClientAppSettings, dataCube: ClientDataCube): Essence {
const { version, encodedModel, visualization } = getHashSegments(hash);
const urlEncoder = definitionUrlEncoders[version];
const definitionConverter = definitionConverters[version];
const definition = urlEncoder.decodeUrlHash(encodedModel, visualization);
- return definitionConverter.fromViewDefinition(definition, dataCube);
+ return definitionConverter.fromViewDefinition(definition, appSettings, dataCube);
},
toHash(essence: Essence, version: ViewDefinitionVersion = DEFAULT_VIEW_DEFINITION_VERSION): string {
diff --git a/src/common/view-definitions/test/essence.fixture.ts b/src/common/view-definitions/test/essence.fixture.ts
index 9367b28cb..e35ff2b1c 100644
--- a/src/common/view-definitions/test/essence.fixture.ts
+++ b/src/common/view-definitions/test/essence.fixture.ts
@@ -16,6 +16,7 @@
import { day, Duration, Timezone } from "chronoshift";
import { OrderedSet } from "immutable";
+import { clientAppSettings } from "../../models/app-settings/app-settings.fixtures";
import { Essence, EssenceValue } from "../../models/essence/essence";
import { RelativeTimeFilterClause, TimeFilterPeriod } from "../../models/filter-clause/filter-clause";
import { Filter } from "../../models/filter/filter";
@@ -61,6 +62,7 @@ const defaults: EssenceOptions = {
export function mockEssence(opts: Partial = {}) {
return new Essence({
+ appSettings: clientAppSettings,
dataCube,
...defaults,
...opts
diff --git a/src/common/view-definitions/version-2/view-definition-converter-2.mocha.ts b/src/common/view-definitions/version-2/view-definition-converter-2.mocha.ts
index bc3e45975..f0c60752a 100644
--- a/src/common/view-definitions/version-2/view-definition-converter-2.mocha.ts
+++ b/src/common/view-definitions/version-2/view-definition-converter-2.mocha.ts
@@ -15,6 +15,7 @@
*/
import { expect } from "chai";
+import { clientAppSettings } from "../../models/app-settings/app-settings.fixtures";
import { wikiClientDataCube } from "../../models/data-cube/data-cube.fixtures";
import { TimeFilterPeriod } from "../../models/filter-clause/filter-clause";
import { stringIn, timePeriod } from "../../models/filter-clause/filter-clause.fixtures";
@@ -64,7 +65,7 @@ describe("ViewDefinitionConverter2", () => {
].forEach(({ label, expression, period }) => {
it(`converts ${label} bucket expression to time period`, () => {
const viewDefinition = ViewDefinitionConverter2Fixtures.withFilterExpression(expression);
- const essence = new ViewDefinitionConverter2().fromViewDefinition(viewDefinition, wikiClientDataCube);
+ const essence = new ViewDefinitionConverter2().fromViewDefinition(viewDefinition, clientAppSettings, wikiClientDataCube);
const convertedClause = essence.filter.clauses.first();
const expectedClause = timePeriod("time", "P1D", period);
@@ -125,7 +126,7 @@ describe("ViewDefinitionConverter2", () => {
}
}
]);
- const convertedFilter = new ViewDefinitionConverter2().fromViewDefinition(viewDefinition, wikiClientDataCube).filter;
+ const convertedFilter = new ViewDefinitionConverter2().fromViewDefinition(viewDefinition, clientAppSettings, wikiClientDataCube).filter;
const convertedClause = convertedFilter.clauses.get(1);
const expectedClause = stringIn("page_last_author", ["TypeScript"]);
@@ -160,7 +161,7 @@ describe("ViewDefinitionConverter2", () => {
limit: 10
}
}]);
- const convertedSplits = new ViewDefinitionConverter2().fromViewDefinition(viewDefinition, wikiClientDataCube).splits;
+ const convertedSplits = new ViewDefinitionConverter2().fromViewDefinition(viewDefinition, clientAppSettings, wikiClientDataCube).splits;
expect(convertedSplits.getSplit(0).reference).to.equal("page_last_author");
});
diff --git a/src/common/view-definitions/version-2/view-definition-converter-2.ts b/src/common/view-definitions/version-2/view-definition-converter-2.ts
index 95a99bfb6..62e589320 100644
--- a/src/common/view-definitions/version-2/view-definition-converter-2.ts
+++ b/src/common/view-definitions/version-2/view-definition-converter-2.ts
@@ -33,6 +33,7 @@ import {
TimeRange,
TimeRangeExpression
} from "plywood";
+import { ClientAppSettings } from "../../models/app-settings/app-settings";
import { ClientDataCube } from "../../models/data-cube/data-cube";
import { DateRange } from "../../models/date-range/date-range";
import { Dimension } from "../../models/dimension/dimension";
@@ -65,7 +66,7 @@ export type FilterSelection = Expression | string;
export class ViewDefinitionConverter2 implements ViewDefinitionConverter {
version = 2;
- fromViewDefinition(definition: ViewDefinition2, dataCube: ClientDataCube): Essence {
+ fromViewDefinition(definition: ViewDefinition2, appSettings: ClientAppSettings, dataCube: ClientDataCube): Essence {
const visualization = manifestByName(definition.visualization);
const visualizationSettings = visualization.visualizationSettings.defaults;
@@ -79,6 +80,7 @@ export class ViewDefinitionConverter2 implements ViewDefinitionConverter {
version = 3;
- fromViewDefinition(definition: ViewDefinition3, dataCube: ClientDataCube): Essence {
+ fromViewDefinition(definition: ViewDefinition3, appSettings: ClientAppSettings, dataCube: ClientDataCube): Essence {
const timezone = Timezone.fromJS(definition.timezone);
const visualization = manifestByName(definition.visualization);
@@ -48,6 +49,7 @@ export class ViewDefinitionConverter3 implements ViewDefinitionConverter converter.fromViewDefinition(viewDef, dataCube);
+export const toEssence = (viewDef: ViewDefinition4) => converter.fromViewDefinition(viewDef, clientAppSettings, dataCube);
export function assertConversionToEssence(viewDef: ViewDefinition4, essence: Essence) {
assertEqlEssence(toEssence(viewDef), essence);
diff --git a/src/common/view-definitions/version-4/view-definition-converter-4.ts b/src/common/view-definitions/version-4/view-definition-converter-4.ts
index 9b2fd27cb..269decdfd 100644
--- a/src/common/view-definitions/version-4/view-definition-converter-4.ts
+++ b/src/common/view-definitions/version-4/view-definition-converter-4.ts
@@ -16,6 +16,7 @@
import { Timezone } from "chronoshift";
import { List, OrderedSet } from "immutable";
+import { ClientAppSettings } from "../../models/app-settings/app-settings";
import { ClientDataCube } from "../../models/data-cube/data-cube";
import { Essence } from "../../models/essence/essence";
import { Filter } from "../../models/filter/filter";
@@ -33,7 +34,7 @@ import { fromViewDefinition, toViewDefinition } from "./visualization-settings-c
export class ViewDefinitionConverter4 implements ViewDefinitionConverter {
version = 4;
- fromViewDefinition(definition: ViewDefinition4, dataCube: ClientDataCube): Essence {
+ fromViewDefinition(definition: ViewDefinition4, appSettings: ClientAppSettings, dataCube: ClientDataCube): Essence {
const timezone = Timezone.fromJS(definition.timezone);
const visualization = manifestByName(definition.visualization);
@@ -69,6 +70,7 @@ export class ViewDefinitionConverter4 implements ViewDefinitionConverter {
version: number;
- fromViewDefinition(definition: VD, dataCube: ClientDataCube): E;
+ fromViewDefinition(definition: VD, appSettings: ClientAppSettings, dataCube: ClientDataCube): E;
toViewDefinition(essence: E): VD;
}
diff --git a/src/common/visualization-manifests/bar-chart/bar-chart.ts b/src/common/visualization-manifests/bar-chart/bar-chart.ts
index 9d217c824..2445593d8 100644
--- a/src/common/visualization-manifests/bar-chart/bar-chart.ts
+++ b/src/common/visualization-manifests/bar-chart/bar-chart.ts
@@ -49,7 +49,7 @@ const rulesEvaluator = visualizationDependentEvaluatorBuilder
})
.when(Predicates.areExactSplitKinds("time", "*"))
- .then(({ splits, series, dataCube }) => {
+ .then(({ splits, series, dataCube, appSettings }) => {
const timeSplit = splits.getSplit(0);
const nominalSplit = splits.getSplit(1);
const nominalDimension = findDimensionByName(dataCube.dimensions, nominalSplit.reference);
@@ -58,21 +58,21 @@ const rulesEvaluator = visualizationDependentEvaluatorBuilder
// Switch splits in place and conform
splits: new Splits({
splits: List([
- adjustColorSplit(nominalSplit, nominalDimension, series),
+ adjustColorSplit(nominalSplit, nominalDimension, series, appSettings.customization.visualizationColors),
adjustContinuousTimeSplit(timeSplit)
])
})
});
})
.when(Predicates.areExactSplitKinds("*", "time"))
- .then(({ splits, series, dataCube, isSelectedVisualization }) => {
+ .then(({ splits, series, dataCube, isSelectedVisualization, appSettings }) => {
const timeSplit = splits.getSplit(1);
const nominalSplit = splits.getSplit(0);
const nominalDimension = findDimensionByName(dataCube.dimensions, nominalSplit.reference);
const newSplits = new Splits({
splits: List([
- adjustColorSplit(nominalSplit, nominalDimension, series),
+ adjustColorSplit(nominalSplit, nominalDimension, series, appSettings.customization.visualizationColors),
adjustContinuousTimeSplit(timeSplit)
])
});
diff --git a/src/common/visualization-manifests/line-chart/line-chart.ts b/src/common/visualization-manifests/line-chart/line-chart.ts
index f13b4db53..29ac6ab60 100644
--- a/src/common/visualization-manifests/line-chart/line-chart.ts
+++ b/src/common/visualization-manifests/line-chart/line-chart.ts
@@ -81,7 +81,7 @@ const rulesEvaluator = visualizationDependentEvaluatorBuilder
})
.when(Predicates.areExactSplitKinds("time", "*"))
- .then(({ splits, series, dataCube }) => {
+ .then(({ splits, series, dataCube, appSettings }) => {
const timeSplit = splits.getSplit(0);
const newTimeSplit = timeSplit
@@ -91,7 +91,7 @@ const rulesEvaluator = visualizationDependentEvaluatorBuilder
const colorSplit = splits.getSplit(1);
const colorDimension = findDimensionByName(dataCube.dimensions, colorSplit.reference);
- const newColorSplit = adjustColorSplit(colorSplit, colorDimension, series);
+ const newColorSplit = adjustColorSplit(colorSplit, colorDimension, series, appSettings.customization.visualizationColors);
return Resolve.automatic(8, {
splits: new Splits({ splits: List([newColorSplit, newTimeSplit]) })
@@ -99,20 +99,20 @@ const rulesEvaluator = visualizationDependentEvaluatorBuilder
})
.when(Predicates.areExactSplitKinds("*", "time"))
- .then(({ splits, series, dataCube }) => {
+ .then(({ splits, series, dataCube, appSettings }) => {
const timeSplit = splits.getSplit(1);
const newTimeSplit = adjustContinuousTimeSplit(timeSplit);
const colorSplit = splits.getSplit(0);
const colorDimension = findDimensionByName(dataCube.dimensions, colorSplit.reference);
- const newColorSplit = adjustColorSplit(colorSplit, colorDimension, series);
+ const newColorSplit = adjustColorSplit(colorSplit, colorDimension, series, appSettings.customization.visualizationColors);
const newSplits = new Splits({ splits: List([newColorSplit, newTimeSplit]) });
if (newSplits.equals(splits)) return Resolve.ready(10);
return Resolve.automatic(8, { splits: newSplits });
})
.when(Predicates.areExactSplitKinds("*", "number"))
- .then(({ splits, dataCube, series }) => {
+ .then(({ splits, dataCube, series, appSettings }) => {
const numberSplit = splits.getSplit(1);
const numberDimension = findDimensionByName(dataCube.dimensions, numberSplit.reference);
@@ -120,7 +120,7 @@ const rulesEvaluator = visualizationDependentEvaluatorBuilder
const colorSplit = splits.getSplit(0);
const colorDimension = findDimensionByName(dataCube.dimensions, colorSplit.reference);
- const newColorSplit = adjustColorSplit(colorSplit, colorDimension, series);
+ const newColorSplit = adjustColorSplit(colorSplit, colorDimension, series, appSettings.customization.visualizationColors);
const newSplits = new Splits({ splits: List([newColorSplit, newNumberSplit]) });
if (newSplits.equals(splits)) return Resolve.ready(10);
diff --git a/src/server/app.ts b/src/server/app.ts
index 338d1e593..6a42ecfd4 100644
--- a/src/server/app.ts
+++ b/src/server/app.ts
@@ -148,7 +148,7 @@ export default function createApp(serverSettings: ServerSettings, settingsManage
attachRouter("/sources", sourcesRouter(settingsManager.sourcesGetter));
attachRouter("/plywood", plywoodRouter(settingsManager));
attachRouter("/plyql", plyqlRouter(settingsManager.sourcesGetter));
- attachRouter("/mkurl", mkurlRouter(settingsManager.sourcesGetter));
+ attachRouter("/mkurl", mkurlRouter(settingsManager.appSettings, settingsManager.sourcesGetter));
attachRouter("/shorten", shortenRouter(settingsManager.appSettings, isTrustedProxy));
attachRouter("/", turniloRouter(settingsManager.appSettings, () => settingsManager.getTimekeeper(), version));
diff --git a/src/server/routes/mkurl/mkurl.mocha.ts b/src/server/routes/mkurl/mkurl.mocha.ts
index 0eca618cd..7e02950b3 100644
--- a/src/server/routes/mkurl/mkurl.mocha.ts
+++ b/src/server/routes/mkurl/mkurl.mocha.ts
@@ -19,6 +19,7 @@ import * as bodyParser from "body-parser";
import express from "express";
import { $ } from "plywood";
import supertest from "supertest";
+import { appSettings } from "../../../common/models/app-settings/app-settings.fixtures";
import { wikiSourcesWithExecutor } from "../../../common/models/sources/sources.fixtures";
import { UrlHashConverterFixtures } from "../../../common/utils/url-hash-converter/url-hash-converter.fixtures";
import { mkurlRouter } from "./mkurl";
@@ -29,7 +30,7 @@ const app = express();
app.use(bodyParser.json());
-app.use(mkurlPath, mkurlRouter(() => Promise.resolve(wikiSourcesWithExecutor)));
+app.use(mkurlPath, mkurlRouter(appSettings, () => Promise.resolve(wikiSourcesWithExecutor)));
describe("mkurl router", () => {
it("gets a simple url back", (testComplete: any) => {
diff --git a/src/server/routes/mkurl/mkurl.ts b/src/server/routes/mkurl/mkurl.ts
index 3f26d8fea..076d0f6a2 100644
--- a/src/server/routes/mkurl/mkurl.ts
+++ b/src/server/routes/mkurl/mkurl.ts
@@ -16,15 +16,28 @@
*/
import { Request, Response, Router } from "express";
+import { deserialize } from "../../../client/deserializers/app-settings";
+import { AppSettings, ClientAppSettings, serialize } from "../../../common/models/app-settings/app-settings";
import { ClientDataCube } from "../../../common/models/data-cube/data-cube";
-import { isQueryable } from "../../../common/models/data-cube/queryable-data-cube";
+import { isQueryable, QueryableDataCube } from "../../../common/models/data-cube/queryable-data-cube";
import { Essence } from "../../../common/models/essence/essence";
import { getDataCube, Sources } from "../../../common/models/sources/sources";
import { urlHashConverter } from "../../../common/utils/url-hash-converter/url-hash-converter";
import { definitionConverters, ViewDefinitionVersion } from "../../../common/view-definitions";
import { SourcesGetter } from "../../utils/settings-manager/settings-manager";
-export function mkurlRouter(sourcesGetter: SourcesGetter) {
+function convertToClientAppSettings(appSettings: AppSettings): ClientAppSettings {
+ return deserialize(serialize(appSettings));
+}
+
+function convertToClientDataCube(cube: QueryableDataCube): ClientDataCube {
+ return {
+ ...cube,
+ timeAttribute: cube.timeAttribute && cube.timeAttribute.name
+ };
+}
+
+export function mkurlRouter(appSettings: AppSettings, sourcesGetter: SourcesGetter) {
const router = Router();
@@ -72,14 +85,12 @@ export function mkurlRouter(sourcesGetter: SourcesGetter) {
return;
}
- let essence: Essence;
- const clientDataCube: ClientDataCube = {
- ...myDataCube,
- timeAttribute: myDataCube.timeAttribute && myDataCube.timeAttribute.name
- };
+ const clientDataCube = convertToClientDataCube(myDataCube);
+ const clientAppSettings = convertToClientAppSettings(appSettings);
+ let essence: Essence;
try {
- essence = definitionConverter.fromViewDefinition(viewDefinition, clientDataCube);
+ essence = definitionConverter.fromViewDefinition(viewDefinition, clientAppSettings, clientDataCube);
} catch ({ message }) {
res.status(400).send({ error: "invalid viewDefinition object", message });
return;
|