Skip to content

Commit

Permalink
feat: config panel and propagating to visualisation
Browse files Browse the repository at this point in the history
JIRA: F1-277
  • Loading branch information
hackerstanislav committed Apr 17, 2024
1 parent d037496 commit 14f317c
Show file tree
Hide file tree
Showing 9 changed files with 349 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// (C) 2019-2024 GoodData Corporation
import React from "react";
import { injectIntl, WrappedComponentProps } from "react-intl";

import DropdownControl from "../DropdownControl.js";
import { confidenceDropdownItems } from "../../../constants/dropdowns.js";
import { getTranslatedDropdownItems } from "../../../utils/translations.js";
import { IVisualizationProperties } from "../../../interfaces/Visualization.js";
import { messages } from "../../../../locales.js";

export interface IForecastConfidenceControl {
disabled: boolean;
value: string;
showDisabledMessage: boolean;
properties: IVisualizationProperties;
pushData: (data: any) => any;
}

class ForecastConfidenceControl extends React.PureComponent<
IForecastConfidenceControl & WrappedComponentProps
> {
public render() {
return (
<DropdownControl
value={this.props.value}
valuePath="forecast.confidence"
labelText={messages.forecastConfidence.id}
disabled={this.props.disabled}
properties={this.props.properties}
pushData={this.props.pushData}
items={this.generateDropdownItems()}
showDisabledMessage={this.props.showDisabledMessage}
/>
);
}

private generateDropdownItems() {
return getTranslatedDropdownItems(confidenceDropdownItems, this.props.intl);
}
}

export default injectIntl(ForecastConfidenceControl);
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// (C) 2019-2024 GoodData Corporation
import React from "react";
import ConfigSection from "../ConfigSection.js";
import ForecastConfidenceControl from "./ForecastConfidenceControl.js";
import { IVisualizationProperties } from "../../../interfaces/Visualization.js";
import InputControl from "../InputControl.js";
import { messages } from "../../../../locales.js";
import noop from "lodash/noop.js";
import CheckboxControl from "../CheckboxControl.js";

export interface IForecastSection {
controlsDisabled: boolean;
enabled: boolean;
properties: IVisualizationProperties;
propertiesMeta: any;
defaultForecastEnabled?: boolean;
pushData: (data: any) => any;
}

class ForecastSection extends React.PureComponent<IForecastSection> {
public static defaultProps: IForecastSection = {
controlsDisabled: false,
enabled: false,
properties: {},
propertiesMeta: {},
defaultForecastEnabled: true,
pushData: noop,
};

public render() {
const { controlsDisabled, properties, pushData, defaultForecastEnabled, enabled } = this.props;

const forecastEnabled = this.props.properties?.controls?.forecast?.enabled ?? defaultForecastEnabled;
const forecastConfidence = this.props.properties?.controls?.forecast?.confidence ?? "95";
const forecastPeriod = this.props.properties?.controls?.forecast?.period ?? 3;
const forecastSeasonal = this.props.properties?.controls?.forecast?.seasonal ?? false;
const forecastToggleDisabledByVisualization = !(this.props.propertiesMeta?.forecast_enabled ?? true);

const toggleDisabled = controlsDisabled || forecastToggleDisabledByVisualization || !enabled;
const forecastControlsDisabled = !forecastEnabled || toggleDisabled;
const showDisabledMessage = controlsDisabled || forecastToggleDisabledByVisualization || !enabled;

return (
<ConfigSection
id="forecast_section"
valuePath="forecast.enabled"
title={messages.forecastTitle.id}
propertiesMeta={this.props.propertiesMeta}
properties={properties}
canBeToggled={true}
toggleDisabled={toggleDisabled}
toggledOn={forecastEnabled}
pushData={pushData}
showDisabledMessage={showDisabledMessage}
toggleMessageId={messages.forecastDisabledTooltip.id}
>
<InputControl
value={forecastPeriod}
valuePath="forecast.period"
labelText={messages.forecastPeriod.id}
placeholder={messages.forecastPeriodPlaceholder.id}
disabled={forecastControlsDisabled}
properties={properties}
pushData={pushData}
/>
<ForecastConfidenceControl
disabled={forecastControlsDisabled}
value={forecastConfidence}
showDisabledMessage={showDisabledMessage}
properties={properties}
pushData={pushData}
/>
<CheckboxControl
valuePath="forecast.seasonal"
checked={forecastSeasonal}
labelText={messages.forecastSeasonal.id}
disabled={forecastControlsDisabled}
properties={properties}
pushData={pushData}
/>
</ConfigSection>
);
}
}

export default ForecastSection;
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
// (C) 2019-2024 GoodData Corporation
import React from "react";
import noop from "lodash/noop.js";
import { ChartType, DefaultLocale } from "@gooddata/sdk-ui";
import { IInsightDefinition, insightHasMeasures, ISettings } from "@gooddata/sdk-model";
import { ChartType, DefaultLocale, BucketNames } from "@gooddata/sdk-ui";
import {
IInsightDefinition,
ISettings,
insightHasMeasures,
insightBuckets,
bucketsFind,
} from "@gooddata/sdk-model";

import {
IReferences,
Expand All @@ -15,6 +21,7 @@ import LegendSection from "../configurationControls/legend/LegendSection.js";
import { InternalIntlWrapper } from "../../utils/internalIntlProvider.js";
import { getMeasuresFromMdObject } from "../../utils/bucketHelper.js";
import InteractionsSection from "../configurationControls/interactions/InteractionsSection.js";
import ForecastSection from "../configurationControls/forecast/ForecastSection.js";

export interface IConfigurationPanelContentProps<PanelConfig = any> {
properties?: IVisualizationProperties;
Expand Down Expand Up @@ -119,4 +126,33 @@ export default abstract class ConfigurationPanelContent<
/>
) : null;
}

protected renderForecastSection(): React.ReactNode {
const { pushData, properties, propertiesMeta, insight, type, featureFlags } = this.props;

if (!featureFlags.enableSmartFunctions) {
return null;
}

//line chart only now
if (type === "line") {
const buckets = insightBuckets(insight);
const measures = bucketsFind(buckets, (b) => b.localIdentifier === BucketNames.MEASURES);
const trends = bucketsFind(buckets, (b) => b.localIdentifier === BucketNames.TREND);
//TODO: check if the trend is date attribute somehow
const enabled = measures?.items.length === 1 && trends?.items.length === 1;

return (
<ForecastSection
controlsDisabled={this.isControlDisabled()}
properties={properties}
propertiesMeta={propertiesMeta}
enabled={enabled}
pushData={pushData}
/>
);
}

return null;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// (C) 2019-2023 GoodData Corporation
// (C) 2019-2024 GoodData Corporation
import React from "react";
import { FormattedMessage } from "react-intl";
import { Bubble, BubbleHoverTrigger } from "@gooddata/sdk-ui-kit";
Expand Down Expand Up @@ -87,6 +87,7 @@ export default class LineChartBasedConfigurationPanel extends BaseChartConfigura
pushData={pushData}
/>
</ConfigSection>
{this.renderForecastSection()}
</div>
<Bubble
className={this.getBubbleClassNames()}
Expand Down
9 changes: 9 additions & 0 deletions libs/sdk-ui-ext/src/internal/constants/dropdowns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ export const formatDropdownItems: IDropdownItem[] = [
},
];

export const confidenceDropdownItems: IDropdownItem[] = [
{ title: messages.forecastConfidence70.id, value: "70" },
{ title: messages.forecastConfidence75.id, value: "75" },
{ title: messages.forecastConfidence80.id, value: "80" },
{ title: messages.forecastConfidence85.id, value: "85" },
{ title: messages.forecastConfidence90.id, value: "90" },
{ title: messages.forecastConfidence95.id, value: "95" },
];

export const legendPositionDropdownItems: IDropdownItem[] = [
{ title: messages.autoDefault.id, value: "auto" },
{ type: "separator" },
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// (C) 2019-2023 GoodData Corporation
// (C) 2019-2024 GoodData Corporation
import { AXIS } from "./axis.js";
import { HeadlineControlProperties } from "../interfaces/ControlProperties.js";
import { CalculateAs } from "@gooddata/sdk-ui-charts";
Expand All @@ -13,6 +13,8 @@ const BASE_PROPERTIES = [
"disableDrillDown",
];

const FORECAST_PROPERTIES = ["forecast"];

const BASE_X_AXIS_PROPERTIES = [
"xaxis.rotation",
"xaxis.labelsEnabled",
Expand Down Expand Up @@ -63,6 +65,7 @@ const CHART_TYPE_PROPERTIES = ["primaryChartType", "secondaryChartType", "dualAx

export const BASE_CHART_SUPPORTED_PROPERTIES = [
...BASE_PROPERTIES,
...FORECAST_PROPERTIES,
...BASE_X_AXIS_PROPERTIES,
...BASE_PRIMARY_AXIS_PROPERTIES,
];
Expand Down
60 changes: 60 additions & 0 deletions libs/sdk-ui-ext/src/internal/translations/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -956,6 +956,66 @@
"comment": "Option of the dropdown for configuring the image sizing of the chart cell (fill)",
"limit": 0
},
"properties.forecast.title": {
"value": "Forecast",
"comment": "",
"limit": 0
},
"properties.forecastDisabled.title": {
"value": "Forecast is not available for this combination of buckets",
"comment": "",
"limit": 0
},
"properties.forecastPeriod.title": {
"value": "Period",
"comment": "",
"limit": 0
},
"properties.forecastPeriod.placeholder": {
"value": "Period",
"comment": "",
"limit": 0
},
"properties.forecastSeasonal.title": {
"value": "Seasonality",
"comment": "",
"limit": 0
},
"properties.forecastConfidence.title": {
"value": "Confidence",
"comment": "",
"limit": 0
},
"properties.forecastConfidence.70": {
"value": "70%",
"comment": "",
"limit": 0
},
"properties.forecastConfidence.75": {
"value": "75%",
"comment": "",
"limit": 0
},
"properties.forecastConfidence.80": {
"value": "80%",
"comment": "",
"limit": 0
},
"properties.forecastConfidence.85": {
"value": "85%",
"comment": "",
"limit": 0
},
"properties.forecastConfidence.90": {
"value": "90%",
"comment": "",
"limit": 0
},
"properties.forecastConfidence.95": {
"value": "95%",
"comment": "",
"limit": 0
},
"properties.canvas.totalLabels": {
"value": "Total Labels",
"comment": "",
Expand Down
12 changes: 12 additions & 0 deletions libs/sdk-ui-ext/src/locales.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,18 @@ export const messages: Record<string, MessageDescriptor> = defineMessages({
image: { id: "properties.canvas.image" },
imageFit: { id: "properties.canvas.image.fit" },
imageFill: { id: "properties.canvas.image.fill" },
forecastTitle: { id: "properties.forecast.title" },
forecastDisabledTooltip: { id: "properties.forecastDisabled.title" },
forecastPeriod: { id: "properties.forecastPeriod.title" },
forecastPeriodPlaceholder: { id: "properties.forecastPeriod.placeholder" },
forecastSeasonal: { id: "properties.forecastSeasonal.title" },
forecastConfidence: { id: "properties.forecastConfidence.title" },
forecastConfidence70: { id: "properties.forecastConfidence.70" },
forecastConfidence75: { id: "properties.forecastConfidence.75" },
forecastConfidence80: { id: "properties.forecastConfidence.80" },
forecastConfidence85: { id: "properties.forecastConfidence.85" },
forecastConfidence90: { id: "properties.forecastConfidence.90" },
forecastConfidence95: { id: "properties.forecastConfidence.95" },
});

export const comparisonMessages: Record<string, MessageDescriptor> = defineMessages({
Expand Down
Loading

0 comments on commit 14f317c

Please sign in to comment.