Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ function drawLineOrBarOrRadarChartValues(
if (isNaN(value)) {
continue;
}
const valueToDisplay = options.callback(Number(value), dataset, i);
if (valueToDisplay === "") {
continue;
}

const point = dataset.data[i];
const xPosition = point.x;
Expand Down Expand Up @@ -122,7 +126,6 @@ function drawLineOrBarOrRadarChartValues(

ctx.fillStyle = point.options.backgroundColor;
ctx.strokeStyle = options.background || "#ffffff";
const valueToDisplay = options.callback(Number(value), dataset, i);
drawTextWithBackground(valueToDisplay, xPosition, yPosition, ctx);
}
}
Expand Down
23 changes: 23 additions & 0 deletions src/components/icons/icons.xml
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,11 @@
<i class="fa fa-trash"/>
</div>
</t>
<t t-name="o-spreadsheet-Icon.CLOSE">
<div class="o-icon">
<i class="fa fa-times"/>
</div>
</t>
<t t-name="o-spreadsheet-Icon.REFRESH">
<div class="o-icon">
<i class="fa fa-refresh"/>
Expand Down Expand Up @@ -1048,4 +1053,22 @@
/>
</svg>
</t>
<t t-name="o-spreadsheet-Icon.LABEL_TAG">
<svg class="o-icon" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<path
stroke="currentColor"
fill="none"
stroke-linecap="round"
d="m7.707 2.793-5.5 5.5a1 1 0 0 0 0 1.414l4.086 4.086a1 1 0 0 0 1.414 0l5.5-5.5a1 1 0 0 0 .293-.707V3.5a1 1 0 0 0-1-1H8.414a1 1 0 0 0-.707.293zM5 9.5l2.75-2.75M6.5 11l1.25-1.25"
/>
<path fill="currentColor" d="M11.5 5a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0"/>
</svg>
</t>
<t t-name="o-spreadsheet-Icon.POINT_SIZE">
<svg fill="currentColor" class="o-icon" viewBox="0 0 15 15" xmlns="http://www.w3.org/2000/svg">
<path
d="M2.8 2.2c-.1-.1-.2-.1-.3-.1s-.2 0-.3.1l-2 2q-.15.3 0 .6.3.15.6 0l1.3-1.3v8L.8 10.2q-.3-.15-.6 0-.15.3 0 .6l2 2c.1 0 .2.1.3.1s.2-.1.3-.1l2-2q.15-.3 0-.6-.3-.15-.6 0l-1.3 1.3v-8l1.3 1.3q.3.15.6 0 .15-.3 0-.6zm2.7 5.3a4.5 4.5 0 0 1 9 0 4.5 4.5 0 0 1-9 0 h1 a3.5 3.5 0 0 0 7 0 a3.5 3.5 0 0 0 -7 0"
/>
</svg>
</t>
</templates>
3 changes: 3 additions & 0 deletions src/components/selection_input/selection_input.css
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,7 @@
font-size: calc(100% + 4px);
}
}
.o-selection-extension {
margin-bottom: -10px;
}
}
33 changes: 33 additions & 0 deletions src/components/selection_input/selection_input.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { Component, onWillUpdateProps, useEffect, useRef, useState } from "@odoo/owl";
import { ActionSpec } from "../../actions/action";
import { deepEquals, range } from "../../helpers";
import { Store, useLocalStore } from "../../store_engine";
import { Color, SpreadsheetChildEnv } from "../../types";
import { cssPropertiesToCss } from "../helpers/css";
import { useDragAndDropListItems } from "../helpers/drag_and_drop_dom_items_hook";
import { updateSelectionWithArrowKeys } from "../helpers/selection_helpers";
import { CogWheelMenu } from "../side_panel/components/cog_wheel_menu/cog_wheel_menu";
import { RangeInputValue, SelectionInputStore } from "./selection_input_store";

interface Props {
Expand All @@ -20,6 +22,8 @@ interface Props {
colors?: Color[];
disabledRanges?: boolean[];
disabledRangeTitle?: string;
getRowMenuItems?: (index: number) => ActionSpec[] | undefined;
getRowExtensions?: (index: number) => SelectionInputRowExtension[] | undefined;
}

type SelectionRangeEditMode = "select-range" | "text-edit";
Expand All @@ -35,6 +39,20 @@ interface SelectionRange extends Omit<RangeInputValue, "color"> {
color?: Color;
disabled?: boolean;
}

export interface SelectionInputRowExtension {
key: string;
title?: string;
icon?: string;
ranges: string[];
hasSingleRange?: boolean;
isInvalid?: boolean;
onSelectionChanged?: (ranges: string[]) => void;
onSelectionConfirmed?: () => void;
onSelectionRemoved?: (index: number) => void;
onRemoveExtension?: () => void;
removeLabel?: string;
}
/**
* This component can be used when the user needs to input some
* ranges. He can either input the ranges with the regular DOM `<input/>`
Expand All @@ -58,7 +76,10 @@ export class SelectionInput extends Component<Props, SpreadsheetChildEnv> {
colors: { type: Array, optional: true, default: [] },
disabledRanges: { type: Array, optional: true, default: [] },
disabledRangeTitle: { type: String, optional: true },
getRowMenuItems: { type: Function, optional: true },
getRowExtensions: { type: Function, optional: true },
};
static components = { CogWheelMenu, SelectionInput };
private state: State = useState({
isMissing: false,
mode: "select-range",
Expand Down Expand Up @@ -92,6 +113,18 @@ export class SelectionInput extends Component<Props, SpreadsheetChildEnv> {
return this.store.disabledRanges.some(Boolean);
}

getRowMenuItems(index: number): ActionSpec[] {
return this.props.getRowMenuItems?.(index) || [];
}

hasMenu(index: number): boolean {
return this.getRowMenuItems(index).length > 0;
}

getRowExtensions(index: number): SelectionInputRowExtension[] {
return this.props.getRowExtensions?.(index) || [];
}

setup() {
useEffect(
() => this.focusedInput.el?.focus(),
Expand Down
126 changes: 82 additions & 44 deletions src/components/selection_input/selection_input.xml
Original file line number Diff line number Diff line change
@@ -1,58 +1,96 @@
<templates>
<t t-name="o-spreadsheet-SelectionInput">
<div class="o-selection" t-ref="o-selection">
<div class="o-selection w-100" t-ref="o-selection">
<div
t-foreach="ranges"
t-as="range"
t-key="range.id"
class="o-selection-input d-flex flex-row"
class="o-selection-input"
t-att-style="dragAndDrop.itemsStyle[range.id]"
t-att-class="props.class">
<span
t-if="ranges.length > 1 and props.onSelectionReordered"
title="Reorder range"
t-on-pointerdown="(ev) => this.startDragAndDrop(range.id, ev)"
class="o-drag-handle d-flex align-items-center mb-2 o-button-icon">
<t t-call="o-spreadsheet-Icon.SHORT_THIN_DRAG_HANDLE"/>
</span>
<div class="position-relative w-100">
<input
type="text"
spellcheck="false"
placeholder="e.g. A1:A2"
t-on-input="(ev) => this.onInputChanged(range.id, ev)"
t-on-focus="() => this.focus(range.id)"
t-on-keydown="onKeydown"
t-att-value="range.xc"
t-att-style="getColor(range)"
class="o-input mb-2"
t-att-class="{
'o-disabled-ranges' : range.disabled and !range.isFocused,
'o-focused' : range.isFocused,
'o-invalid border-danger position-relative': isInvalid || !range.isValidRange,
'text-decoration-underline': range.xc and range.isFocused and state.mode === 'select-range'
}"
t-ref="{{range.isFocused ? 'focusedInput' : 'unfocusedInput' + range_index}}"
/>
<div class="d-flex">
<span
t-if="isInvalid || !range.isValidRange"
class="input-icon text-danger position-absolute d-flex align-items-center"
title="This range is invalid">
<t t-call="o-spreadsheet-Icon.ERROR"/>
</span>
<span
class="input-icon o-disabled-ranges position-absolute d-flex align-items-center"
t-if="!range.isFocused and range.disabled"
t-att-title="props.disabledRangeTitle">
<t t-call="o-spreadsheet-Icon.CIRCLE_INFO"/>
t-if="ranges.length > 1 and props.onSelectionReordered"
title="Reorder range"
t-on-pointerdown="(ev) => this.startDragAndDrop(range.id, ev)"
class="o-drag-handle d-flex align-items-center mb-2 o-button-icon">
<t t-call="o-spreadsheet-Icon.SHORT_THIN_DRAG_HANDLE"/>
</span>
<div class="position-relative w-100">
<input
type="text"
spellcheck="false"
placeholder="e.g. A1:A2"
t-on-input="(ev) => this.onInputChanged(range.id, ev)"
t-on-focus="() => this.focus(range.id)"
t-on-keydown="onKeydown"
t-att-value="range.xc"
t-att-style="getColor(range)"
class="o-input mb-2"
t-att-class="{
'o-disabled-ranges' : range.disabled and !range.isFocused,
'o-focused' : range.isFocused,
'o-invalid border-danger position-relative': isInvalid || !range.isValidRange,
'text-decoration-underline': range.xc and range.isFocused and state.mode === 'select-range'
}"
t-ref="{{range.isFocused ? 'focusedInput' : 'unfocusedInput' + range_index}}"
/>
<span
t-if="isInvalid || !range.isValidRange"
class="input-icon text-danger position-absolute d-flex align-items-center"
title="This range is invalid">
<t t-call="o-spreadsheet-Icon.ERROR"/>
</span>
<span
class="input-icon o-disabled-ranges position-absolute d-flex align-items-center"
t-if="!range.isFocused and range.disabled"
t-att-title="props.disabledRangeTitle">
<t t-call="o-spreadsheet-Icon.CIRCLE_INFO"/>
</span>
</div>
<div class="ms-2 d-flex align-items-center">
<CogWheelMenu t-if="hasMenu(range_index)" items="getRowMenuItems(range_index)"/>
<button
class="border-0 bg-transparent fw-bold o-remove-selection o-button-icon pe-0"
t-if="ranges.length > 1"
t-on-click="() => this.removeInput(range.id)">
<t t-call="o-spreadsheet-Icon.TRASH_FILLED"/>
</button>
</div>
</div>
<div t-if="props.getRowExtensions" class="mb-2">
<t t-set="extensions" t-value="getRowExtensions(range_index)"/>
<t t-if="extensions.length">
<div
class="o-selection-extension ms-4 d-flex align-items-start"
t-foreach="extensions"
t-as="extension"
t-key="extension.key"
t-att-title="extension.title">
<div class="mb-2 me-2 mt-2">
<t t-call="{{extension.icon}}"/>
</div>
<div class="flex-grow-1">
<SelectionInput
ranges="extension.ranges"
hasSingleRange="extension.hasSingleRange"
isInvalid="extension.isInvalid"
onSelectionChanged="extension.onSelectionChanged"
onSelectionConfirmed="extension.onSelectionConfirmed"
onSelectionRemoved="extension.onSelectionRemoved"
class="'mt-0'"
/>
</div>
<div
class="o-remove-extension ms-0 mt-2 me-3"
t-if="extension.onRemoveExtension"
t-att-title="extension.removeLabel"
t-on-click="() => extension.onRemoveExtension()">
</div>
</div>
</t>
</div>
<button
class="border-0 bg-transparent fw-bold o-remove-selection o-button-icon pe-0"
t-if="ranges.length > 1"
t-on-click="() => this.removeInput(range.id)">
<t t-call="o-spreadsheet-Icon.TRASH_FILLED"/>
</button>
</div>
<div class="d-flex flex-row w-100 o-selection-input">
<button class="o-button o-add-selection" t-if="canAddRange" t-on-click="addEmptyInput">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import { Component } from "@odoo/owl";
import { ActionSpec } from "../../../../../actions/action";
import { _t } from "../../../../../translation";
import {
ChartDatasetOrientation,
Color,
CustomizedDataSet,
SpreadsheetChildEnv,
} from "../../../../../types";
import { SelectionInput } from "../../../../selection_input/selection_input";
import {
SelectionInput,
SelectionInputRowExtension,
} from "../../../../selection_input/selection_input";
import { Section } from "../../../components/section/section";

interface Props {
Expand All @@ -21,6 +25,8 @@ interface Props {
datasetOrientation?: ChartDatasetOrientation;
canChangeDatasetOrientation?: boolean;
onFlipAxis?: (structure: string) => void;
getRangeMenuItems?: (index: number) => ActionSpec[] | undefined;
getRangeExtensions?: (index: number) => SelectionInputRowExtension[] | undefined;
}

export class ChartDataSeries extends Component<Props, SpreadsheetChildEnv> {
Expand All @@ -38,6 +44,8 @@ export class ChartDataSeries extends Component<Props, SpreadsheetChildEnv> {
datasetOrientation: { type: String, optional: true },
canChangeDatasetOrientation: { type: Boolean, optional: true },
onFlipAxis: { type: Function, optional: true },
getRangeMenuItems: { type: Function, optional: true },
getRangeExtensions: { type: Function, optional: true },
};

get ranges(): string[] {
Expand All @@ -60,4 +68,16 @@ export class ChartDataSeries extends Component<Props, SpreadsheetChildEnv> {
}
return this.props.hasSingleRange ? _t("Data range") : _t("Data series");
}

getRangeMenuItems(index: number): ActionSpec[] {
return this.props.getRangeMenuItems?.(index) || [];
}

hasMenu(index: number): boolean {
return this.getRangeMenuItems(index).length > 0;
}

getRangeExtensions(index: number): SelectionInputRowExtension[] {
return this.props.getRangeExtensions?.(index) || [];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
colors="colors"
disabledRanges="disabledRanges"
disabledRangeTitle.translate="Excluded due to chart limits. Drag to swap with another range."
getRowMenuItems="props.getRangeMenuItems"
getRowExtensions="props.getRangeExtensions"
/>
</Section>
</t>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import { Component } from "@odoo/owl";
import {
ChartWithDataSetDefinition,
DispatchResult,
SpreadsheetChildEnv,
UID,
} from "../../../../../types";
import { DispatchResult, SpreadsheetChildEnv, UID } from "../../../../../types";
import { Checkbox } from "../../../components/checkbox/checkbox";

type PartialDefinition = {
readonly showValues?: boolean;
readonly showValuesMode?: string;
[key: string]: any;
};

interface Props {
chartId: UID;
definition: ChartWithDataSetDefinition;
updateChart: (chartId: UID, definition: Partial<ChartWithDataSetDefinition>) => DispatchResult;
canUpdateChart: (chartId: UID, definition: Partial<ChartWithDataSetDefinition>) => DispatchResult;
definition: PartialDefinition;
updateChart: (chartId: UID, definition: PartialDefinition) => DispatchResult;
canUpdateChart: (chartId: UID, definition: PartialDefinition) => DispatchResult;
defaultValue?: boolean;
modes?: { value: string; label: string }[];
onModeChanged?: (type: string) => void;
}

export class ChartShowValues extends Component<Props, SpreadsheetChildEnv> {
Expand All @@ -26,5 +29,20 @@ export class ChartShowValues extends Component<Props, SpreadsheetChildEnv> {
updateChart: Function,
canUpdateChart: Function,
defaultValue: { type: Boolean, optional: true },
modes: { type: Array, optional: true },
onModeChanged: { type: Function, optional: true },
};

get shouldShowValues(): boolean {
return this.props.definition.showValues ?? this.props.defaultValue ?? false;
}

get shouldShowOptions(): boolean {
return !!this.props.modes?.length && !!this.props.onModeChanged;
}

onModeChanged(ev: Event) {
const value = (ev.target as HTMLSelectElement).value;
this.props.onModeChanged?.(value);
}
}
Loading