@odoo/o-spreadsheet 17.5.0-alpha.7 → 18.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,9 @@
1
1
  <!--
2
2
  This file is generated by o-spreadsheet build tools. Do not edit it.
3
3
  @see https://github.com/odoo/o-spreadsheet
4
- @version 17.5.0-alpha.7
5
- @date 2024-08-26T13:50:08.744Z
6
- @hash f8d3f23
4
+ @version 18.1.0-alpha.0
5
+ @date 2024-09-25T13:18:46.133Z
6
+ @hash 288f0b7
7
7
  -->
8
8
  <odoo>
9
9
  <t t-name="o-spreadsheet-ActionButton">
@@ -189,7 +189,7 @@
189
189
  t-if="state.isSheetListScrollableLeft"
190
190
  />
191
191
  <div
192
- class="o-sheet-list d-flex w-100 overflow-hidden px-1"
192
+ class="o-sheet-list d-flex w-100 px-1"
193
193
  t-ref="sheetList"
194
194
  t-on-wheel="onWheel"
195
195
  t-on-scroll="onScroll">
@@ -284,8 +284,19 @@
284
284
  <span class="o-sheet-icon ms-1" t-on-click.stop="(ev) => this.onIconClick(ev)">
285
285
  <t t-call="o-spreadsheet-Icon.CARET_DOWN"/>
286
286
  </span>
287
+ <div
288
+ t-if="sheetColorStyle"
289
+ class="o-sheet-color position-absolute"
290
+ t-att-style="sheetColorStyle"
291
+ />
287
292
  </div>
288
293
  </Ripple>
294
+ <ColorPicker
295
+ t-if="state.pickerOpened"
296
+ anchorRect="colorPickerAnchorRect"
297
+ onColorPicked.bind="onColorPicked"
298
+ currentColor="props.currentColor"
299
+ />
289
300
  </t>
290
301
 
291
302
  <t t-name="o-spreadsheet-BottomBarStatistic">
@@ -456,37 +467,71 @@
456
467
 
457
468
  <t t-name="o-spreadsheet-Composer">
458
469
  <div class="o-composer-container w-100 h-100">
459
- <div
460
- class="o-composer w-100 text-start"
461
- t-att-class="{ 'text-muted': env.model.getters.isReadonly(), 'active': props.focus !== 'inactive' }"
462
- t-att-style="props.inputStyle"
463
- t-ref="o_composer"
464
- tabindex="1"
465
- t-att-contenteditable="env.model.getters.isReadonly() ? 'false' : 'true'"
466
- t-att-placeHolder="props.placeholder"
467
- spellcheck="false"
468
- t-on-keydown="onKeydown"
469
- t-on-mousewheel.stop=""
470
- t-on-input="onInput"
471
- t-on-pointerdown="onMousedown"
472
- t-on-click="onClick"
473
- t-on-keyup="onKeyup"
474
- t-on-paste="onPaste"
475
- t-on-compositionstart="onCompositionStart"
476
- t-on-compositionend="onCompositionEnd"
477
- t-on-dblclick="onDblClick"
478
- t-on-contextmenu="onContextMenu"
479
- t-on-blur="onBlur"
470
+ <t
471
+ t-set="assistantIsAvailable"
472
+ t-value="autoCompleteState.provider or functionDescriptionState.showDescription"
480
473
  />
481
-
474
+ <div class="d-flex flex-row position-relative">
475
+ <span
476
+ t-if="props.focus !== 'inactive' and assistantIsAvailable and assistant.forcedClosed"
477
+ role="button"
478
+ title="Show formula help"
479
+ t-on-click="openAssistant"
480
+ t-on-pointerdown.prevent.stop=""
481
+ t-on-click.prevent.stop=""
482
+ t-on-pointerup.prevent.stop=""
483
+ class="fa-stack position-absolute translate-middle force-open-assistant fs-4">
484
+ <i class="fa fa-circle fa-stack-1x fa-inverse"/>
485
+ <i class="fa fa-question-circle fa-stack-1x"/>
486
+ </span>
487
+ <div
488
+ class="o-composer w-100 text-start"
489
+ t-att-class="{ 'text-muted': env.model.getters.isReadonly(), 'active': props.focus !== 'inactive' }"
490
+ t-att-style="props.inputStyle"
491
+ t-ref="o_composer"
492
+ tabindex="1"
493
+ t-att-contenteditable="env.model.getters.isReadonly() ? 'false' : 'true'"
494
+ t-att-placeHolder="props.placeholder"
495
+ spellcheck="false"
496
+ t-on-keydown="onKeydown"
497
+ t-on-mousewheel.stop=""
498
+ t-on-input="onInput"
499
+ t-on-pointerdown="onMousedown"
500
+ t-on-click="onClick"
501
+ t-on-keyup="onKeyup"
502
+ t-on-paste="onPaste"
503
+ t-on-compositionstart="onCompositionStart"
504
+ t-on-compositionend="onCompositionEnd"
505
+ t-on-dblclick="onDblClick"
506
+ t-on-contextmenu="onContextMenu"
507
+ t-on-blur="onBlur"
508
+ />
509
+ </div>
482
510
  <div
483
- t-if="props.focus !== 'inactive' and (autoCompleteState.provider or functionDescriptionState.showDescription)"
511
+ t-if="props.focus !== 'inactive' and !assistant.forcedClosed and assistantIsAvailable"
484
512
  class="o-composer-assistant shadow"
485
513
  t-att-style="assistantStyle"
486
514
  t-on-wheel.stop=""
487
515
  t-on-pointerdown.prevent.stop=""
488
516
  t-on-click.prevent.stop=""
489
517
  t-on-pointerup.prevent.stop="">
518
+ <span
519
+ role="button"
520
+ t-on-click="closeAssistant"
521
+ class="fa-stack position-absolute top-0 start-100 translate-middle fs-4">
522
+ <i class="fa fa-circle fa-stack-1x fa-inverse"/>
523
+ <i class="fa fa-times-circle fa-stack-1x text-muted"/>
524
+ </span>
525
+ <FunctionDescriptionProvider
526
+ t-if="functionDescriptionState.showDescription"
527
+ functionName="functionDescriptionState.functionName"
528
+ functionDescription="functionDescriptionState.functionDescription"
529
+ argToFocus="functionDescriptionState.argToFocus"
530
+ />
531
+ <div
532
+ t-if="functionDescriptionState.showDescription and autoCompleteState.provider"
533
+ class="border-top"
534
+ />
490
535
  <TextValueProvider
491
536
  t-if="autoCompleteState.provider"
492
537
  proposals="autoCompleteState.provider.proposals"
@@ -494,71 +539,65 @@
494
539
  onValueSelected.bind="this.autoComplete"
495
540
  onValueHovered.bind="this.updateAutoCompleteIndex"
496
541
  />
497
- <FunctionDescriptionProvider
498
- t-if="functionDescriptionState.showDescription"
499
- functionName="functionDescriptionState.functionName"
500
- functionDescription="functionDescriptionState.functionDescription"
501
- argToFocus="functionDescriptionState.argToFocus"
502
- />
503
542
  </div>
504
543
  </div>
505
544
  </t>
506
545
 
507
546
  <t t-name="o-spreadsheet-FunctionDescriptionProvider">
508
- <div
509
- class="o-formula-assistant-container user-select-none shadow"
510
- t-att-class="{
511
- 'pe-none': assistantState.allowCellSelectionBehind,
512
- 'pe-auto': !assistantState.allowCellSelectionBehind
513
- }">
547
+ <div class="o-formula-assistant-container user-select-none shadow">
514
548
  <t t-set="context" t-value="getContext()"/>
515
- <div
516
- class="o-formula-assistant"
517
- t-if="context.functionName"
518
- t-on-pointermove="onMouseMove"
519
- t-att-class="{'opacity-25': assistantState.allowCellSelectionBehind}">
520
- <div class="o-formula-assistant-head">
521
- <span t-esc="context.functionName"/>
522
- (
523
- <t t-foreach="context.functionDescription.args" t-as="arg" t-key="arg.name">
524
- <span t-if="arg_index > '0'" t-esc="formulaArgSeparator"/>
525
- <span t-att-class="{ 'o-formula-assistant-focus': context.argToFocus === arg_index }">
526
- <span>
527
- <span t-if="arg.optional || arg.repeating || arg.default">[</span>
528
- <span t-esc="arg.name"/>
529
- <span t-if="arg.repeating">, ...</span>
530
- <span t-if="arg.optional || arg.repeating || arg.default">]</span>
549
+ <div class="o-formula-assistant" t-if="context.functionName">
550
+ <div class="o-formula-assistant-head d-flex flex-row justify-content-between">
551
+ <div>
552
+ <span t-esc="context.functionName"/>
553
+ (
554
+ <t t-foreach="context.functionDescription.args" t-as="arg" t-key="arg.name">
555
+ <span t-if="arg_index > '0'" t-esc="formulaArgSeparator"/>
556
+ <span t-att-class="{ 'o-formula-assistant-focus': context.argToFocus === arg_index }">
557
+ <span>
558
+ <span t-if="arg.optional || arg.repeating || arg.default">[</span>
559
+ <span t-esc="arg.name"/>
560
+ <span t-if="arg.repeating">, ...</span>
561
+ <span t-if="arg.optional || arg.repeating || arg.default">]</span>
562
+ </span>
531
563
  </span>
532
- </span>
533
- </t>
534
- )
564
+ </t>
565
+ )
566
+ </div>
567
+ <i
568
+ class="fa fa-caret-up px-2 align-self-start collapsed"
569
+ data-bs-toggle="collapse"
570
+ data-bs-target="#formula-assistant-details"
571
+ />
535
572
  </div>
536
573
 
537
- <div class="o-formula-assistant-core pb-3 m-3">
538
- <div class="o-formula-assistant-gray">ABOUT</div>
539
- <div t-esc="context.functionDescription.description"/>
540
- </div>
574
+ <div id="formula-assistant-details" class="collapse">
575
+ <div class="o-formula-assistant-core pb-3 m-3">
576
+ <div class="o-formula-assistant-gray">ABOUT</div>
577
+ <div t-esc="context.functionDescription.description"/>
578
+ </div>
541
579
 
542
- <t t-foreach="context.functionDescription.args" t-as="arg" t-key="arg.name">
543
- <div
544
- class="o-formula-assistant-arg p-3 pt-0 display-flex flex-column"
545
- t-att-class="{
546
- 'o-formula-assistant-gray': context.argToFocus >= '0',
547
- 'o-formula-assistant-focus': context.argToFocus === arg_index,
548
- }">
549
- <div>
550
- <span t-esc="arg.name"/>
551
- <span
552
- t-if="arg.optional || arg.repeating || arg.default ">&#xA0;- [optional]&#xA0;</span>
553
- <span t-if="arg.default">
554
- <span>default:&#xA0;</span>
555
- <t t-esc="arg.defaultValue"/>
556
- </span>
557
- <span t-if="arg.repeating">repeatable</span>
580
+ <t t-foreach="context.functionDescription.args" t-as="arg" t-key="arg.name">
581
+ <div
582
+ class="o-formula-assistant-arg p-3 pt-0 display-flex flex-column"
583
+ t-att-class="{
584
+ 'o-formula-assistant-gray': context.argToFocus >= '0',
585
+ 'o-formula-assistant-focus': context.argToFocus === arg_index,
586
+ }">
587
+ <div>
588
+ <span t-esc="arg.name"/>
589
+ <span
590
+ t-if="arg.optional || arg.repeating || arg.default ">&#xA0;- [optional]&#xA0;</span>
591
+ <span t-if="arg.default">
592
+ <span>default:&#xA0;</span>
593
+ <t t-esc="arg.defaultValue"/>
594
+ </span>
595
+ <span t-if="arg.repeating">repeatable</span>
596
+ </div>
597
+ <div class="o-formula-assistant-arg-description" t-esc="arg.description"/>
558
598
  </div>
559
- <div class="o-formula-assistant-arg-description" t-esc="arg.description"/>
560
- </div>
561
- </t>
599
+ </t>
600
+ </div>
562
601
  </div>
563
602
  </div>
564
603
  </t>
@@ -684,11 +723,15 @@
684
723
  </t>
685
724
 
686
725
  <t t-name="o-spreadsheet-GaugeChartComponent">
687
- <canvas class="o-figure-canvas w-100 h-100" t-ref="chartContainer"/>
726
+ <canvas class="o-figure-canvas o-gauge-chart w-100 h-100" t-ref="chartContainer"/>
688
727
  </t>
689
728
 
690
729
  <t t-name="o-spreadsheet-ScorecardChart">
691
- <canvas class="o-figure-canvas w-100 h-100" t-ref="chartContainer" t-att-title="title"/>
730
+ <canvas
731
+ class="o-figure-canvas o-scorecard w-100 h-100"
732
+ t-ref="chartContainer"
733
+ t-att-title="title"
734
+ />
692
735
  </t>
693
736
 
694
737
  <t t-name="o-spreadsheet-FigureComponent">
@@ -2054,6 +2097,11 @@
2054
2097
  />
2055
2098
  </svg>
2056
2099
  </t>
2100
+ <t t-name="o-spreadsheet-Icon.SMALL_DOT_RIGHT_ALIGN">
2101
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18 18">
2102
+ <circle fill="currentColor" cx="14" cy="9" r="4"/>
2103
+ </svg>
2104
+ </t>
2057
2105
  <t t-name="o-spreadsheet-Icon.SORT_RANGE">
2058
2106
  <svg class="o-icon">
2059
2107
  <path
@@ -2412,8 +2460,10 @@
2412
2460
  disabled="1"
2413
2461
  />
2414
2462
  </t>
2415
- <button t-if="link.url" t-on-click="removeLink" class="o-remove-url">✖</button>
2416
- <button t-if="!link.url" t-on-click.stop="openMenu" class="o-special-link">
2463
+ <button t-if="link.url" t-on-click="removeLink" class="o-remove-url o-button-icon">
2464
+
2465
+ </button>
2466
+ <button t-if="!link.url" t-on-click.stop="openMenu" class="o-special-link o-button-icon">
2417
2467
  <t t-call="o-spreadsheet-Icon.LIST"/>
2418
2468
  </button>
2419
2469
  </div>
@@ -2463,7 +2513,8 @@
2463
2513
  <div class="d-flex w-100">
2464
2514
  <div
2465
2515
  t-if="childrenHaveIcon"
2466
- class="o-menu-item-icon d-flex align-items-center flex-shrink-0">
2516
+ class="o-menu-item-icon d-flex align-items-center flex-shrink-0"
2517
+ t-att-style="getIconColor(menuItem)">
2467
2518
  <t t-if="getIconName(menuItem)" t-call="{{getIconName(menuItem)}}"/>
2468
2519
  </div>
2469
2520
  <div class="o-menu-item-name align-middle text-truncate" t-esc="getName(menuItem)"/>
@@ -2559,7 +2610,7 @@
2559
2610
  t-att-class="{
2560
2611
  'o-focused' : range.isFocused,
2561
2612
  'o-invalid border-danger position-relative': isInvalid || !range.isValidRange,
2562
- 'text-decoration-underline': range.isFocused and state.mode === 'select-range'
2613
+ 'text-decoration-underline': range.xc and range.isFocused and state.mode === 'select-range'
2563
2614
  }"
2564
2615
  t-ref="{{range.isFocused ? 'focusedInput' : 'unfocusedInput' + range_index}}"
2565
2616
  />
@@ -2571,7 +2622,7 @@
2571
2622
  </span>
2572
2623
  </div>
2573
2624
  <button
2574
- class="o-btn border-0 bg-transparent fw-bold o-remove-selection o-text-muted pe-0"
2625
+ class="border-0 bg-transparent fw-bold o-remove-selection o-button-icon pe-0"
2575
2626
  t-if="ranges.length > 1"
2576
2627
  t-on-click="() => this.removeInput(range.id)">
2577
2628
  <t t-call="o-spreadsheet-Icon.TRASH_FILLED"/>
@@ -3108,7 +3159,7 @@
3108
3159
  <t t-set-slot="title">Values</t>
3109
3160
  <Checkbox
3110
3161
  name="'showValues'"
3111
- label="showValuesLabel"
3162
+ label.translate="Show values"
3112
3163
  value="props.definition.showValues"
3113
3164
  onChange="showValues => props.updateChart(this.props.figureId, {showValues})"
3114
3165
  />
@@ -3263,7 +3314,7 @@
3263
3314
  definition="props.definition"
3264
3315
  updateChart="props.updateChart"
3265
3316
  />
3266
- <SidePanelCollapsible collapsedAtInit="true">
3317
+ <SidePanelCollapsible collapsedAtInit="false">
3267
3318
  <t t-set-slot="title">Gauge Design</t>
3268
3319
  <t t-set-slot="content">
3269
3320
  <Section class="'pt-0'">
@@ -3308,6 +3359,7 @@
3308
3359
  <tr>
3309
3360
  <th class="o-gauge-color-set-colorPicker"/>
3310
3361
  <th class="o-gauge-color-set-text"/>
3362
+ <th class="o-gauge-color-set-operator"/>
3311
3363
  <th class="o-gauge-color-set-value">Value</th>
3312
3364
  <th class="o-gauge-color-set-type">Type</th>
3313
3365
  </tr>
@@ -3352,7 +3404,20 @@
3352
3404
  onColorPicked="(color) => this.updateSectionColor(sectionType, color)"
3353
3405
  />
3354
3406
  </td>
3355
- <td>When value is below</td>
3407
+ <td>When value is</td>
3408
+ <td class="pe-2">
3409
+ <t t-set="below">below</t>
3410
+ <t t-set="belowOrEqualTo">below or equal to</t>
3411
+ <select
3412
+ class="o-input"
3413
+ name="operatorType"
3414
+ t-att-title="inflectionPoint.operator === '&lt;' ? below : belowOrEqualTo"
3415
+ t-model="inflectionPoint.operator"
3416
+ t-on-change="() => this.updateSectionRule(state.sectionRule)">
3417
+ <option title="below" value="&lt;">&lt;</option>
3418
+ <option title="below or equal to" value="&lt;=">&lt;=</option>
3419
+ </select>
3420
+ </td>
3356
3421
  <td class="pe-2">
3357
3422
  <input
3358
3423
  type="text"
@@ -3478,7 +3543,7 @@
3478
3543
  <t t-set-slot="title">Values</t>
3479
3544
  <Checkbox
3480
3545
  name="'showValues'"
3481
- label="showValuesLabel"
3546
+ label.translate="Show values"
3482
3547
  value="props.definition.showValues"
3483
3548
  onChange="showValues => props.updateChart(this.props.figureId, {showValues})"
3484
3549
  />
@@ -3564,7 +3629,7 @@
3564
3629
  </Section>
3565
3630
  </t>
3566
3631
  </GeneralDesignEditor>
3567
- <SidePanelCollapsible collapsedAtInit="true">
3632
+ <SidePanelCollapsible collapsedAtInit="false">
3568
3633
  <t t-set-slot="title">Baseline</t>
3569
3634
  <t t-set-slot="content">
3570
3635
  <Section class="'pt-0'">
@@ -3632,7 +3697,7 @@
3632
3697
  <t t-set-slot="title">Values</t>
3633
3698
  <Checkbox
3634
3699
  name="'showValues'"
3635
- label="showValuesLabel"
3700
+ label.translate="Show values"
3636
3701
  value="props.definition.showValues"
3637
3702
  onChange="showValues => props.updateChart(this.props.figureId, {showValues})"
3638
3703
  />
@@ -3741,7 +3806,7 @@
3741
3806
 
3742
3807
  <t t-name="o-spreadsheet-CogWheelMenu">
3743
3808
  <span
3744
- class="fa fa-cog o-text-muted os-cog-wheel-menu-icon"
3809
+ class="fa fa-cog os-cog-wheel-menu-icon o-button-icon"
3745
3810
  t-on-click="toggleMenu"
3746
3811
  t-ref="button"
3747
3812
  />
@@ -3784,16 +3849,22 @@
3784
3849
  </t>
3785
3850
 
3786
3851
  <t t-name="o-spreadsheet.RadioSelection">
3787
- <div class="d-flex flex-row">
3852
+ <div
3853
+ class="d-flex"
3854
+ t-att-class="{
3855
+ 'flex-row': props.direction === 'horizontal',
3856
+ 'flex-column': props.direction === 'vertical'}">
3788
3857
  <t t-foreach="props.choices" t-as="choice" t-key="choice.value">
3789
3858
  <label class="o-radio d-flex align-items-center me-4">
3790
3859
  <input
3791
- class="me-1"
3860
+ t-att-class="{
3861
+ 'me-1': props.direction === 'horizontal',
3862
+ 'me-2': props.direction === 'vertical'}"
3792
3863
  type="radio"
3793
3864
  t-att-name="props.name"
3794
3865
  t-att-value="choice.value"
3795
3866
  t-att-checked="choice.value === props.selectedValue"
3796
- t-on-change="onChange"
3867
+ t-on-change="() => props.onChange(choice.value)"
3797
3868
  />
3798
3869
  <t t-esc="choice.label"/>
3799
3870
  </label>
@@ -3954,6 +4025,9 @@
3954
4025
  <t t-if="state.currentCFType === 'IconSetRule'" t-call="o-spreadsheet-IconSetEditor">
3955
4026
  <t t-set="rule" t-value="state.rules.iconSet"/>
3956
4027
  </t>
4028
+ <t t-if="state.currentCFType === 'DataBarRule'" t-call="o-spreadsheet-DataBarEditor">
4029
+ <t t-set="rule" t-value="state.rules.dataBar"/>
4030
+ </t>
3957
4031
  </Section>
3958
4032
  <Section class="'pt-1'">
3959
4033
  <div class="o-sidePanelButtons">
@@ -4046,6 +4120,25 @@
4046
4120
  </div>
4047
4121
  </t>
4048
4122
 
4123
+ <t t-name="o-spreadsheet-DataBarEditor">
4124
+ <div class="o-cf-data-bar-editor">
4125
+ <div class="o-section-subtitle">Color</div>
4126
+ <RoundColorPicker
4127
+ currentColor="colorNumberString(rule.color)"
4128
+ onColorPicked.bind="updateDataBarColor"
4129
+ />
4130
+ <div class="o-section-subtitle">Range of values</div>
4131
+ <SelectionInput
4132
+ ranges="getRangeValues()"
4133
+ class="'o-range'"
4134
+ isInvalid="false"
4135
+ hasSingleRange="true"
4136
+ onSelectionChanged="(ranges) => this.onDataBarRangeUpdate(ranges)"
4137
+ required="false"
4138
+ />
4139
+ </div>
4140
+ </t>
4141
+
4049
4142
  <t t-name="o-spreadsheet-IconSets">
4050
4143
  <div class="pb-2">
4051
4144
  <div class="o-section-subtitle">Icons</div>
@@ -4163,11 +4256,13 @@
4163
4256
  <div class="o-cf-iconset-rule">
4164
4257
  <t t-call="o-spreadsheet-IconSets"/>
4165
4258
  <t t-call="o-spreadsheet-IconSetInflexionPoints"/>
4166
- <div
4167
- class="btn btn-link ps-0 o-cf-iconset-reverse d-flex flex-row align-items-center"
4168
- t-on-click="reverseIcons">
4169
- <t t-call="o-spreadsheet-Icon.REFRESH"/>
4170
- <div class="ms-1">Reverse icons</div>
4259
+ <div class="d-flex flex-row">
4260
+ <div
4261
+ class="o-button-link py-1 ps-0 o-cf-iconset-reverse d-flex align-items-center"
4262
+ t-on-click="reverseIcons">
4263
+ <t t-call="o-spreadsheet-Icon.REFRESH"/>
4264
+ <div class="ms-1">Reverse icons</div>
4265
+ </div>
4171
4266
  </div>
4172
4267
  </div>
4173
4268
  </t>
@@ -4182,7 +4277,8 @@
4182
4277
  t-on-click="props.onPreviewClick"
4183
4278
  t-on-pointerdown="(ev) => this.onMouseDown(ev)">
4184
4279
  <div class="position-relative h-100 w-100 d-flex align-items-center">
4185
- <div class="o-cf-drag-handle h-100 position-absolute d-flex align-items-center text-muted">
4280
+ <div
4281
+ class="o-cf-drag-handle h-100 position-absolute d-flex align-items-center o-button-icon">
4186
4282
  <t t-call="o-spreadsheet-Icon.THIN_DRAG_HANDLE"/>
4187
4283
  </div>
4188
4284
  <t t-if="cf.rule.type==='IconSetRule'">
@@ -4209,10 +4305,10 @@
4209
4305
  </div>
4210
4306
  <div class="o-cf-delete">
4211
4307
  <div
4212
- class="o-cf-delete-button text-muted"
4308
+ class="o-cf-delete-button o-button-icon"
4213
4309
  t-on-click.stop="(ev) => this.deleteConditionalFormat(cf, ev)"
4214
4310
  title="Remove rule">
4215
- <t t-call="o-spreadsheet-Icon.TRASH"/>
4311
+ <t t-call="o-spreadsheet-Icon.TRASH_FILLED"/>
4216
4312
  </div>
4217
4313
  </div>
4218
4314
  </div>
@@ -4234,7 +4330,7 @@
4234
4330
  </div>
4235
4331
  </t>
4236
4332
  <div
4237
- class="btn btn-link o-sidePanel-btn-link o-cf-add float-end"
4333
+ class="o-button-link p-4 o-cf-add float-end"
4238
4334
  t-on-click.prevent.stop="props.onAddConditionalFormat">
4239
4335
  + Add another rule
4240
4336
  </div>
@@ -4297,7 +4393,7 @@
4297
4393
  <Section>
4298
4394
  <t t-set-slot="title">Format</t>
4299
4395
  <select
4300
- class="o-input o-format-proposals"
4396
+ class="o-input o-format-proposals mb-1"
4301
4397
  t-on-change="(ev) => this.updateSelectFormat(ev)"
4302
4398
  t-att-disabled="!formatProposals.length">
4303
4399
  <t t-foreach="formatProposals" t-as="proposal" t-key="proposal_index">
@@ -4308,6 +4404,23 @@
4308
4404
  />
4309
4405
  </t>
4310
4406
  </select>
4407
+ <t t-set="accounting_format_label">Accounting format</t>
4408
+ <Checkbox
4409
+ name="'accountingFormat'"
4410
+ label="accounting_format_label"
4411
+ value="state.isAccountingFormat"
4412
+ onChange.bind="toggleAccountingFormat"
4413
+ />
4414
+ <div class="o-format-examples mt-4" t-if="selectedFormat">
4415
+ <table>
4416
+ <t t-foreach="getFormatExamples()" t-as="example" t-key="example_index">
4417
+ <tr>
4418
+ <td class="pe-3 fw-bolder" t-esc="example.label"/>
4419
+ <td t-esc="example.value"/>
4420
+ </tr>
4421
+ </t>
4422
+ </table>
4423
+ </div>
4311
4424
  </Section>
4312
4425
  <Section>
4313
4426
  <div class="o-sidePanelButtons">
@@ -4333,9 +4446,7 @@
4333
4446
  />
4334
4447
  </t>
4335
4448
  </div>
4336
- <div
4337
- class="o-dv-add btn btn-link o-sidePanel-btn-link float-end"
4338
- t-on-click="addDataValidationRule">
4449
+ <div class="o-dv-add o-button-link p-4 float-end" t-on-click="addDataValidationRule">
4339
4450
  + Add another rule
4340
4451
  </div>
4341
4452
  </t>
@@ -4425,9 +4536,9 @@
4425
4536
  onBlur.bind="onBlurInput"
4426
4537
  />
4427
4538
  <div
4428
- class="o-dv-list-item-delete ms-2 me-1"
4539
+ class="o-dv-list-item-delete ms-2 o-button-icon"
4429
4540
  t-on-click="() => this.removeItem(value_index)">
4430
- <t t-call="o-spreadsheet-Icon.TRASH"/>
4541
+ <t t-call="o-spreadsheet-Icon.TRASH_FILLED"/>
4431
4542
  </div>
4432
4543
  </div>
4433
4544
  <div class="mb-2"/>
@@ -4521,9 +4632,9 @@
4521
4632
  <div class="o-dv-preview-ranges text-truncate" t-esc="rangesString"/>
4522
4633
  </div>
4523
4634
  <div
4524
- class="o-dv-preview-delete d-flex align-items-center text-muted px-3"
4635
+ class="o-dv-preview-delete d-flex align-items-center o-button-icon px-3"
4525
4636
  t-on-click.stop="deleteDataValidation">
4526
- <t t-call="o-spreadsheet-Icon.TRASH"/>
4637
+ <t t-call="o-spreadsheet-Icon.TRASH_FILLED"/>
4527
4638
  </div>
4528
4639
  </div>
4529
4640
  </div>
@@ -4660,16 +4771,14 @@
4660
4771
  <div>
4661
4772
  <input type="text" class="o-input o_sp_en_name" t-model="state.name"/>
4662
4773
  </div>
4663
- <div class="btn btn-link o_sp_en_save" t-on-click="save">Save</div>
4664
- <br/>
4774
+ <div class="o-button-link o_sp_en_save" t-on-click="save">Save</div>
4665
4775
  </t>
4666
4776
  <t t-else="">
4667
4777
  <div class="o_sp_en_display_name" t-esc="props.displayName"/>
4668
- <div class="btn btn-link o_sp_en_rename" t-on-click="rename">
4778
+ <div class="o-button-link o_sp_en_rename" t-on-click="rename">
4669
4779
  <i class="fa fa-pencil me-1"/>
4670
4780
  Rename
4671
4781
  </div>
4672
- <br/>
4673
4782
  </t>
4674
4783
  </t>
4675
4784
 
@@ -4682,14 +4791,14 @@
4682
4791
  value="props.deferUpdate"
4683
4792
  onChange="(value) => props.toggleDeferUpdate(value)"
4684
4793
  />
4685
- <div t-if="props.isDirty">
4794
+ <div t-if="props.isDirty" class="d-flex align-items-center">
4686
4795
  <i
4687
- class="btn btn-sm pe-0 fa fa-undo"
4796
+ class="o-button-icon pe-0 fa fa-undo"
4688
4797
  title="Discard all changes"
4689
4798
  t-on-click="() => props.discard()"
4690
4799
  />
4691
4800
  <span
4692
- class="btn btm-sm btn-link sp_apply_update"
4801
+ class="o-button-link sp_apply_update small ps-2"
4693
4802
  title="Apply all changes"
4694
4803
  t-on-click="() => props.apply()">
4695
4804
  Update
@@ -4703,7 +4812,7 @@
4703
4812
  <Popover t-if="popover.isOpen" t-props="popoverProps">
4704
4813
  <div
4705
4814
  class="p-2 bg-white border-bottom d-flex sticky-top align-items-baseline pivot-dimension-search">
4706
- <i class="pe-1 pivot-dimension-search-field-icon">
4815
+ <i class="pe-1 pivot-dimension-search-field-icon text-muted">
4707
4816
  <t t-call="o-spreadsheet-Icon.SEARCH"/>
4708
4817
  </i>
4709
4818
  <input
@@ -4719,6 +4828,7 @@
4719
4828
  onValueSelected="autoComplete.provider.selectProposal"
4720
4829
  onValueHovered="() => {}"
4721
4830
  />
4831
+ <t t-slot="default" t-on-click="togglePopover"/>
4722
4832
  </Popover>
4723
4833
  </t>
4724
4834
 
@@ -4739,11 +4849,14 @@
4739
4849
  />
4740
4850
  <span t-else="1" class="fw-bold" t-esc="props.dimension.displayName"/>
4741
4851
  </div>
4742
- <i
4743
- class="btn fa fa-trash o-text-muted pe-0 ms-auto"
4744
- t-if="props.onRemoved"
4745
- t-on-click="() => props.onRemoved(props.dimension)"
4746
- />
4852
+ <div class="d-flex flex-rows">
4853
+ <t t-slot="upper-right-icons"/>
4854
+ <i
4855
+ class="o-button-icon fa fa-trash pe-1 ps-2"
4856
+ t-if="props.onRemoved"
4857
+ t-on-click="() => props.onRemoved(props.dimension)"
4858
+ />
4859
+ </div>
4747
4860
  </div>
4748
4861
  <t t-slot="default"/>
4749
4862
  </div>
@@ -4808,11 +4921,11 @@
4808
4921
  class="pt-1">
4809
4922
  <PivotDimension dimension="col" onRemoved.bind="removeDimension">
4810
4923
  <PivotDimensionGranularity
4811
- t-if="isDateField(col)"
4924
+ t-if="isDateOrDatetimeField(col)"
4812
4925
  dimension="col"
4813
4926
  onUpdated.bind="this.updateGranularity"
4814
- availableGranularities="props.unusedDateTimeGranularities[col.fieldName]"
4815
- allGranularities="props.allGranularities"
4927
+ availableGranularities="props.unusedGranularities[col.fieldName]"
4928
+ allGranularities="getGranularitiesFor(col)"
4816
4929
  />
4817
4930
  <PivotDimensionOrder dimension="col" onUpdated.bind="this.updateOrder"/>
4818
4931
  </PivotDimension>
@@ -4834,11 +4947,11 @@
4834
4947
  class="pt-1">
4835
4948
  <PivotDimension dimension="row" onRemoved.bind="removeDimension">
4836
4949
  <PivotDimensionGranularity
4837
- t-if="isDateField(row)"
4950
+ t-if="isDateOrDatetimeField(row)"
4838
4951
  dimension="row"
4839
4952
  onUpdated.bind="this.updateGranularity"
4840
- availableGranularities="props.unusedDateTimeGranularities[row.fieldName]"
4841
- allGranularities="props.allGranularities"
4953
+ availableGranularities="props.unusedGranularities[row.fieldName]"
4954
+ allGranularities="getGranularitiesFor(row)"
4842
4955
  />
4843
4956
  <PivotDimensionOrder dimension="row" onUpdated.bind="this.updateOrder"/>
4844
4957
  </PivotDimension>
@@ -4847,47 +4960,152 @@
4847
4960
  <div
4848
4961
  class="fw-bold pt-4 pb-1 d-flex flex-row justify-content-between align-items-center o-section-title o-pivot-measure">
4849
4962
  Measures
4850
- <AddDimensionButton onFieldPicked.bind="addMeasureDimension" fields="props.measureFields"/>
4963
+ <AddDimensionButton onFieldPicked.bind="addMeasureDimension" fields="props.measureFields">
4964
+ <div
4965
+ t-on-click="addCalculatedMeasure"
4966
+ class="p-2 bg-white border-top d-flex align-items-center sticky-bottom add-calculated-measure">
4967
+ <i class="pe-1">
4968
+ <t t-call="o-spreadsheet-Icon.FORMULA"/>
4969
+ </i>
4970
+ Add calculated measure
4971
+ </div>
4972
+ </AddDimensionButton>
4851
4973
  </div>
4852
4974
  <t t-foreach="props.definition.measures" t-as="measure" t-key="measure.id">
4853
4975
  <div
4854
4976
  t-on-pointerdown="(ev) => this.startDragAndDropMeasures(measure, ev)"
4855
4977
  t-att-style="dragAndDrop.itemsStyle[measure.id]"
4978
+ t-att-class="measure.isHidden ? 'opacity-50' : ''"
4856
4979
  class="pt-1 pivot-measure">
4857
- <PivotDimension
4858
- dimension="measure"
4859
- onRemoved.bind="removeMeasureDimension"
4860
- onNameUpdated.bind="onMeasureNameUpdated">
4861
- <div class="d-flex flex-column small">
4862
- <div class="d-flex py-1 px-2 w-100">
4863
- <div class="pivot-dim-operator-label">Aggregated by</div>
4864
- <select
4865
- class="o-input flex-grow-1 me-3"
4866
- t-on-change="(ev) => this.updateAggregator(measure, ev.target.value)">
4867
- <option
4868
- t-foreach="Object.keys(AGGREGATORS[measure.type])"
4869
- t-as="agg"
4870
- t-key="agg"
4871
- t-att-value="agg"
4872
- t-att-selected="agg === measure.aggregator"
4873
- t-esc="AGGREGATORS[measure.type][agg]"
4874
- />
4875
- </select>
4876
- </div>
4877
- </div>
4878
- </PivotDimension>
4980
+ <PivotMeasureEditor
4981
+ pivotId="props.pivotId"
4982
+ definition="props.definition"
4983
+ measure="measure"
4984
+ aggregators="AGGREGATORS"
4985
+ onRemoved="() => this.removeMeasureDimension(measure)"
4986
+ onMeasureUpdated="(newMeasure) => this.updateMeasure(measure, newMeasure)"
4987
+ generateMeasureId.bind="getMeasureId"
4988
+ />
4879
4989
  </div>
4880
4990
  </t>
4881
4991
  </div>
4882
4992
  </t>
4883
4993
 
4994
+ <t t-name="o-spreadsheet-PivotMeasureEditor">
4995
+ <t t-set="measure" t-value="props.measure"/>
4996
+ <PivotDimension dimension="measure" onRemoved="props.onRemoved" onNameUpdated.bind="updateName">
4997
+ <t t-set-slot="upper-right-icons">
4998
+ <t t-if="measure.isHidden" t-set="hideTitle">Show</t>
4999
+ <t t-else="" t-set="hideTitle">Hide</t>
5000
+ <i
5001
+ t-att-class="measure.isHidden ? 'fa fa-eye-slash': 'fa fa-eye'"
5002
+ t-att-title="hideTitle"
5003
+ class="o-button-icon pe-1 ps-2"
5004
+ t-on-click="toggleMeasureVisibility"
5005
+ />
5006
+ <i
5007
+ class="o-button-icon pe-1 ps-2 fa fa-cog"
5008
+ title="Show values as"
5009
+ t-on-click="openShowValuesAs"
5010
+ />
5011
+ </t>
5012
+ <div t-if="measure.computedBy" class="d-flex flex-row small">
5013
+ <div class="d-flex flex-column py-2 px-2 w-100">
5014
+ <StandaloneComposer
5015
+ onConfirm.bind="updateMeasureFormula"
5016
+ composerContent="measure.computedBy.formula"
5017
+ defaultRangeSheetId="measure.computedBy.sheetId"
5018
+ contextualAutocomplete="getMeasureAutocomplete()"
5019
+ />
5020
+ </div>
5021
+ </div>
5022
+ <div class="d-flex flex-row">
5023
+ <div class="d-flex py-1 px-2 w-100 small">
5024
+ <div class="pivot-dim-operator-label">Aggregated by</div>
5025
+ <select
5026
+ class="o-input flex-grow-1"
5027
+ t-on-change="(ev) => this.updateAggregator(ev.target.value)">
5028
+ <option
5029
+ t-foreach="Object.keys(props.aggregators[measure.type])"
5030
+ t-as="agg"
5031
+ t-key="agg"
5032
+ t-att-value="agg"
5033
+ t-att-selected="agg === measure.aggregator"
5034
+ t-esc="props.aggregators[measure.type][agg]"
5035
+ />
5036
+ </select>
5037
+ </div>
5038
+ </div>
5039
+ </PivotDimension>
5040
+ </t>
5041
+
5042
+ <t t-name="o-spreadsheet-PivotMeasureDisplayPanel">
5043
+ <Section>
5044
+ <t t-set-slot="title">Show measure as:</t>
5045
+ <select
5046
+ class="o-pivot-measure-display-type o-input"
5047
+ t-on-change="(ev) => this.store.updateMeasureDisplayType(ev.target.value)">
5048
+ <t t-foreach="measureDisplayTypeLabels" t-as="measureType" t-key="measureType">
5049
+ <option
5050
+ t-att-value="measureType"
5051
+ t-att-selected="measureType === store.measureDisplay.type"
5052
+ t-esc="measureType_value"
5053
+ />
5054
+ </t>
5055
+ </select>
5056
+ <div
5057
+ class="o-pivot-measure-display-description mt-3 ps-3"
5058
+ t-esc="measureDisplayDescription[store.measureDisplay.type]"
5059
+ />
5060
+ </Section>
5061
+
5062
+ <Section t-if="store.doesDisplayNeedsField">
5063
+ <t t-set-slot="title">Base field:</t>
5064
+ <div class="o-pivot-measure-display-field w-100 py-1 px-3">
5065
+ <t t-if="store.fields.length">
5066
+ <RadioSelection
5067
+ choices="fieldChoices"
5068
+ selectedValue="store.measureDisplay.fieldNameWithGranularity"
5069
+ name="'baseField'"
5070
+ onChange.bind="(val) => store.updateMeasureDisplayField(val)"
5071
+ direction="'vertical'"
5072
+ />
5073
+ </t>
5074
+ <t t-else="">
5075
+ <div class="text-muted text-center my-3">No active dimension in the pivot</div>
5076
+ </t>
5077
+ </div>
5078
+ </Section>
5079
+
5080
+ <t t-set="values" t-value="store.values"/>
5081
+ <Section t-if="store.doesDisplayNeedsValue and values.length">
5082
+ <t t-set-slot="title">Base item:</t>
5083
+ <div class="o-pivot-measure-display-value w-100 py-1 px-3">
5084
+ <RadioSelection
5085
+ choices="values"
5086
+ selectedValue="store.measureDisplay.value"
5087
+ name="'baseValue'"
5088
+ onChange.bind="(val) => store.updateMeasureDisplayValue(val)"
5089
+ direction="'vertical'"
5090
+ />
5091
+ </div>
5092
+ </Section>
5093
+
5094
+ <Section>
5095
+ <div class="o-sidePanelButtons">
5096
+ <button t-on-click="onCancel" class="o-pivot-measure-cancel o-button">Cancel</button>
5097
+ <button t-on-click="onSave" class="o-pivot-measure-save o-button primary">Save</button>
5098
+ </div>
5099
+ </Section>
5100
+ </t>
5101
+
4884
5102
  <t t-name="o-spreadsheet-PivotSidePanel">
4885
5103
  <t t-component="sidePanelEditor" t-props="props"/>
4886
5104
  </t>
4887
5105
 
4888
5106
  <t t-name="o-spreadsheet-PivotSpreadsheetSidePanel">
4889
5107
  <div class="d-flex flex-column h-100 justify-content-between overflow-hidden">
4890
- <div class="h-100 overflow-auto">
5108
+ <div class="h-100 position-relative overflow-x-hidden overflow-y-auto">
4891
5109
  <PivotTitleSection pivotId="props.pivotId" flipAxis.bind="flipAxis"/>
4892
5110
  <Section>
4893
5111
  <t t-set-slot="title">Range</t>
@@ -4910,10 +5128,12 @@
4910
5128
  t-if="!pivot.isInvalidRange"
4911
5129
  unusedGroupableFields="store.unusedGroupableFields"
4912
5130
  measureFields="store.measureFields"
4913
- unusedDateTimeGranularities="store.unusedDateTimeGranularities"
4914
- allGranularities="store.allGranularities"
5131
+ unusedGranularities="store.unusedGranularities"
5132
+ dateGranularities="store.dateGranularities"
5133
+ datetimeGranularities="store.datetimeGranularities"
4915
5134
  definition="definition"
4916
5135
  onDimensionsUpdated.bind="onDimensionsUpdated"
5136
+ pivotId="props.pivotId"
4917
5137
  />
4918
5138
  </div>
4919
5139
  <PivotDeferUpdate
@@ -5033,6 +5253,10 @@
5033
5253
  <span class="fw-bold me-1">Date time:</span>
5034
5254
  <span t-esc="dateTimeFormatPreview"/>
5035
5255
  </div>
5256
+ <div>
5257
+ <span class="fw-bold me-1">First day of week:</span>
5258
+ <span t-esc="firstDayOfWeek"/>
5259
+ </div>
5036
5260
  </div>
5037
5261
  </Section>
5038
5262
  <Section class="'pt-0'">
@@ -5440,7 +5664,11 @@
5440
5664
  t-att-id="props.id"
5441
5665
  t-att-placeholder="props.placeholder"
5442
5666
  t-att-value="props.value"
5443
- t-on-change="onChange"
5667
+ t-on-change="save"
5668
+ t-on-focus="focusInputAndSelectContent"
5669
+ t-on-blur="save"
5670
+ t-on-mouseup.prevent.stop=""
5671
+ t-on-keydown="onKeyDown"
5444
5672
  />
5445
5673
  </div>
5446
5674