[REF] web: KanbanView, review and simplify scss

Review, simplify SCSS and adapt legacy code.
Part of the overall v16 SCSS optimization/restyle, task-2704984

task-2892062

Part-of: odoo/odoo#96195
This commit is contained in:
Brieuc-brd
2022-08-30 17:10:13 +02:00
parent dba33909aa
commit 7cfe50749f
16 changed files with 105 additions and 366 deletions
@@ -45,19 +45,15 @@
// container ghost card in background
.o_kanban_example_background_container {
display: flex;
padding: 0px;
opacity: 0.4;
// content
.o_kanban_example_background {
flex: 1 1 100%;
flex-basis: 100%;
.o_kanban_examples {
.o_kanban_examples_group {
.o_kanban_examples_ghost {
width: 224px;
margin-bottom: 10px;
width: $o-kanban-small-record-width;
}
}
}
@@ -67,31 +63,16 @@
// kanban ghost card
.o_kanban_examples {
display: flex;
padding: 0 6px;
.o_kanban_examples_group {
flex: 1 1 100%;
margin: 10px;
flex-basis: 100%;
.o_kanban_examples_ghost {
padding: 5px;
margin-top: -1px;
border: thin solid map-get($grays, '300');
background-color: white;
.o_ghost_content {
height: 12px;
background: map-get($grays, '300');
&.o_ghost_tag {
display: inline-block;
width: 40%;
margin-top: 10px;
}
&.o_collapse {
margin-top: -1px;
}
.o_ghost_avatar {
height: 20px;
width: 20px;
margin-top: 6px;
}
}
}
@@ -465,7 +465,6 @@
}
.o_kanban_quick_add i {
@include o-kanban-icon;
margin-left: $o-kanban-inside-hgutter*2;
}
@@ -481,10 +480,6 @@
@include media-breakpoint-down(md) {
visibility: visible;
}
i {
@include o-kanban-icon;
}
}
}
@@ -521,7 +516,7 @@
}
.o_column_unfold {
@include o-kanban-icon(1);
display: block;
}
}
@@ -237,14 +237,6 @@
}
// ------- Kanban grouped mixins -------
@mixin o-kanban-icon($base-opacity: 0.5) {
display: block;
text-align: center;
color: $o-main-text-color;
font-size: $font-size-sm;
cursor: pointer;
@include o-hover-opacity($base-opacity);
}
@mixin o-kanban-tag-color {
@for $size from 1 through length($o-colors) {
// Note: the first color is supposed to be invisible if there is a color
@@ -285,8 +277,6 @@
transform-origin: left bottom 0;
transform: rotate(90deg);
overflow: visible;
white-space: nowrap;
font-size: 15px;
}
// ------- Kanban records mixins -------
+19 -19
View File
@@ -13,10 +13,10 @@
role="feed" t-attf-aria-labelledby="kanban_header_#{widget.id or widget.db_id}">
<div class="o_kanban_header">
<div class="o_kanban_header_title">
<span t-attf-id="#kanban_header_#{widget.id or widget.db_id}" class="o_column_title"><t t-esc="widget.title"/></span>
<span class="o_column_unfold"><i class="fa fa-arrows-h" role="img" aria-label="Unfold" title="Unfold"/></span>
<span t-attf-id="#kanban_header_#{widget.id or widget.db_id}" class="o_column_title" t-attf-class="{{ !widget.isMobile and widget.folded ? 'fs-4 overflow-visible' : '' }}"><t t-esc="widget.title"/></span>
<button class="o_column_unfold btn btn-link p-0 border-0 small text-center text-700 cursor-pointer"><i class="fa fa-arrows-h" role="img" aria-label="Unfold" title="Unfold"/></button>
<span class="o_kanban_config dropdown">
<a class="dropdown-toggle o-no-caret" data-bs-toggle="dropdown" href="#"><i class="fa fa-gear" role="img" aria-label="Settings" title="Settings"/></a>
<a class="dropdown-toggle o-no-caret" data-bs-toggle="dropdown" href="#"><i class="fa fa-gear d-block text-center text-700 small opacity-50 opacity-100-hover cursor-pointer" role="img" aria-label="Settings" title="Settings"/></a>
<div class="dropdown-menu cursor-default" role="menu">
<a t-if="!widget.isMobile" role="menuitem" class="dropdown-item o_kanban_toggle_fold" href="#">Fold</a>
<t t-if="widget.grouped_by_m2o">
@@ -29,7 +29,7 @@
</t>
</div>
</span>
<span t-if="widget.quick_create" class="o_kanban_quick_add"><i class="fa fa-plus" role="img" aria-label="Quick add" title="Quick add"/></span>
<a t-if="widget.quick_create" class="o_kanban_quick_add"><i class="fa fa-plus d-block small text-center text-700 opacity-50 opacity-100-hover cursor-pointer" role="img" aria-label="Quick add" title="Quick add"/></a>
</div>
</div>
<div t-if="widget.loadMoreCount > 0" class="o_kanban_load_more">
@@ -57,7 +57,7 @@
</div>
<span t-if="!widget.isMobile" class="o_discard_msg text-muted float-end">Esc to discard</span>
<t t-if="widget.examples &amp;&amp; !widget.isMobile">
<button type="button" class="btn btn-link o_kanban_examples">See examples</button>
<button type="button" class="btn btn-link o_kanban_examples p-0">See examples</button>
</t>
</div>
<div class="o_kanban_muted_record"/>
@@ -157,9 +157,9 @@
<div t-if="example.description" class="o_kanban_examples_description">
<t t-out="example.description"/>
</div>
<div class="o_kanban_examples">
<div class="o_kanban_examples d-flex p-2">
<t t-foreach="example.columns" t-as="column">
<div class="o_kanban_examples_group">
<div class="o_kanban_examples_group flex-grow-1 m-3">
<h6><b><t t-esc="column"/></b></h6>
<t t-foreach="_.random(1,4)">
<t t-call="KanbanView.ExamplesDialog.RecordGhost"/>
@@ -173,23 +173,23 @@
</div>
</div>
<t t-name="KanbanView.ExamplesDialog.RecordGhost">
<div class="o_kanban_examples_ghost">
<div class="o_ghost_content"/>
<div class="o_ghost_content o_ghost_tag"/>
<div class="o_kanban_examples_ghost o_collapse p-2 border bg-white">
<div class="o_ghost_content pb-3 bg-300"/>
<div class="o_ghost_content o_ghost_tag d-inline-block w-50 mt-3 pb-3 bg-300"/>
<t t-if="example.bullets and _.random(0, 5) > 3">
<t t-out="_.sample(example.bullets)"/>
</t>
<img class="float-end o_ghost_avatar" src="/base/static/img/avatar.png" alt="Avatar"/>
<img class="float-end o_ghost_avatar mt-2" src="/base/static/img/avatar.png" alt="Avatar"/>
</div>
</t>
<!-- Kanban Example Background -->
<t t-name="KanbanView.ExamplesBackground">
<div class="o_kanban_example_background_container">
<div class="o_kanban_example_background">
<div class="o_kanban_examples">
<div class="o_kanban_example_background_container d-flex opacity-50">
<div class="o_kanban_example_background flex-grow-1">
<div class="o_kanban_examples d-flex p-2">
<t t-foreach="ghostColumns" t-as="column">
<div class="o_kanban_examples_group">
<div class="o_kanban_examples_group flex-grow-1 m-3">
<h6><b><t t-esc="column"/></b></h6>
<t t-foreach="_.random(2,6)">
<t t-call="KanbanView.ExamplesBackground.RecordGhost"/>
@@ -201,10 +201,10 @@
</div>
</t>
<t t-name="KanbanView.ExamplesBackground.RecordGhost">
<div class="o_kanban_examples_ghost">
<div class="o_ghost_content"/>
<div class="o_ghost_content o_ghost_tag"/>
<img class="float-end o_ghost_avatar" src="/base/static/img/avatar.png" alt="Avatar"/>
<div class="o_kanban_examples_ghost mb-3 p-2 border bg-white">
<div class="o_ghost_content pb-3 bg-300"/>
<div class="o_ghost_content o_ghost_tag d-inline-block w-50 mt-3 pb-3 bg-300"/>
<img class="float-end o_ghost_avatar mt-2" src="/base/static/img/avatar.png" alt="Avatar"/>
</div>
</t>
@@ -2,10 +2,10 @@
<templates xml:space="preserve">
<t t-name="web.KanbanAnimatedNumber" owl="1">
<div class="o_kanban_counter_side" t-att-class="state.value !== props.value and props.animationClass" t-att-title="props.title">
<span t-if="props.currency and props.currency.position === 'before'" t-esc="props.currency.symbol" />
<div class="o_kanban_counter_side ms-2 text-900 text-nowrap" t-att-class="state.value !== props.value and props.animationClass" t-att-title="props.title">
<span t-if="props.currency and props.currency.position === 'before'" t-esc="props.currency.symbol" class="ms-1"/>
<b t-esc="format(state.value)" />
<span t-if="props.currency and props.currency.position === 'after'" t-esc="props.currency.symbol" />
<span t-if="props.currency and props.currency.position === 'after'" t-esc="props.currency.symbol" class="ms-1"/>
</div>
</t>
@@ -3,13 +3,13 @@
<t t-name="web.KanbanExamplesNotebookTemplate" owl="1">
<div t-if="props.description" class="o_kanban_examples_description" t-out="props.description"/>
<div class="o_kanban_examples">
<div class="o_kanban_examples d-flex p-2">
<t t-foreach="columns" t-as="column" t-key="column.title">
<div class="o_kanban_examples_group">
<div class="o_kanban_examples_group flex-grow-1 m-3">
<h6><b t-esc="column.title"/></h6>
<div t-foreach="column.records" t-as="record" t-key="record.id" class="o_kanban_examples_ghost">
<div class="o_ghost_content"/>
<div class="o_ghost_content o_ghost_tag"/>
<div t-foreach="column.records" t-as="record" t-key="record.id" class="o_kanban_examples_ghost p-2 border bg-white" t-att-class="{ 'o_collapse': record_index > 0 }">
<div class="o_ghost_content pb-3 bg-300"/>
<div class="o_ghost_content o_ghost_tag d-inline-block w-50 mt-3 pb-3 bg-300"/>
<span class="ms-2" t-if="record.bullet" t-out="record.bullet"/>
</div>
</div>
@@ -10,21 +10,8 @@
border-color: $mix-full;
}
.progress-bar.bg-#{$class} {
border: 1px solid white;
}
.oe_kanban_card_#{$class} {
order: 1;
margin-bottom: $o-kanban-inside-vgutter*0.5;
~ .oe_kanban_card_#{$class} {
margin-top: -$o-kanban-inside-vgutter*0.5 - 1px;
}
~ .o_kanban_load_more {
margin-top: -$o-kanban-inside-vgutter*0.5;
}
}
.o_kanban_load_more {
@@ -40,47 +27,14 @@
}
}
// If columns has the progressbar, adapt the layout
.o_kanban_view .o_kanban_group.o_kanban_has_progressbar {
> .o_kanban_header .o_kanban_header_title {
height: $o-kanban-header-title-height*0.6;
margin-top: 5px;
}
&.o_kanban_no_records {
.o_kanban_counter {
opacity: 0.3;
}
}
}
.o_kanban_counter {
position: relative;
display: flex;
align-items: center;
transition: opacity 0.3s ease 0s;
margin-bottom: $o-kanban-record-margin*2;
> .o_kanban_counter_progress {
width: 76%;
height: $font-size-sm;
margin-bottom: 0;
background-color: map-get($grays, '300');
box-shadow: none;
.progress-bar {
margin-bottom: 0;
box-shadow: none;
cursor: pointer;
}
}
> .o_kanban_counter_side {
width: 21%;
margin-left: 3%;
color: $headings-color;
text-align: right;
white-space: nowrap;
transform-origin: right center;
&.o_kanban_grow {
@@ -90,53 +44,25 @@
&.o_kanban_grow_huge {
animation: grow_huge 1s ease 0s 1 normal none running;
}
// Target currency icon
> span {
margin-left: 2px;
}
}
}
.o_column_folded .o_kanban_counter {
display: none;
}
.o_kanban_view .o_kanban_group {
@include o-kanban-css-filter(success, map-get($theme-colors, 'success'));
@include o-kanban-css-filter(warning, map-get($theme-colors, 'warning'));
@include o-kanban-css-filter(danger, map-get($theme-colors, 'danger'));
@include o-kanban-css-filter(muted, map-get($theme-colors, 'dark'));
&.o_kanban_group_show {
display: flex;
flex-flow: column nowrap;
> * {
flex: 0 0 auto;
}
}
@include o-kanban-css-filter(info, map-get($theme-colors, 'info'));
}
@keyframes grow {
0% {
transform: scale3d(1, 1, 1);
}
30% {
transform: scale3d(1.1, 1.1, 1.1);
}
100% {
transform: scale3d(1, 1, 1);
}
}
@keyframes grow_huge {
0% {
transform: scale3d(1, 1, 1);
}
30% {
transform: scale3d(1.3, 1.3, 1.3);
}
100% {
transform: scale3d(1, 1, 1);
}
}
@@ -3,16 +3,16 @@
<t t-name="web.KanbanColumnQuickCreate" owl="1">
<div class="o_column_quick_create" t-ref="root">
<div t-if="props.folded" class="o_quick_create_folded" t-on-click="unfold">
<div t-if="props.folded" class="o_quick_create_folded m-3 text-nowrap fw-bold opacity-75 opacity-100-hover" t-on-click="unfold">
<button class="o_kanban_add_column btn btn-outline-secondary w-100">
<i class="fa fa-plus me-2" role="img" aria-label="Add column" title="Add column"/><t t-out="props.groupByFieldString"/>
</button>
</div>
<div t-else="" class="o_quick_create_unfolded">
<div class="o_kanban_header">
<div t-else="" class="o_quick_create_unfolded pt-3 px-2 pb-2">
<div class="o_kanban_header top-0 pb-3">
<div class="input-group">
<input type="text"
class="form-control o_input"
class="form-control o_input bg-transparent fs-4"
t-attf-placeholder="{{ props.groupByFieldString }}..."
t-ref="autofocus"
t-model.trim="state.columnTitle"
@@ -25,14 +25,14 @@
</button>
</span>
</div>
<span t-if="!env.isSmall and state.hasInputFocused" class="o_discard_msg text-muted float-end">
<small t-if="!env.isSmall and state.hasInputFocused" class="o_discard_msg text-muted float-end">
Esc to discard
</span>
</small>
<t t-if="props.exampleData and !env.isSmall">
<button type="button" class="btn btn-link o_kanban_examples" t-on-click="showExamples">See examples</button>
<button type="button" class="btn btn-link o_kanban_examples p-0" t-on-click="showExamples">See examples</button>
</t>
</div>
<div t-foreach="[,,,]" t-as="i" t-key="i_index" class="o_kanban_muted_record" />
<div t-foreach="[,,,]" t-as="i" t-key="i_index" class="o_kanban_muted_record mt-3 py-5 bg-300" />
</div>
</div>
</t>
@@ -1,8 +1,5 @@
// ------- Kanban View Layout -------
.o_kanban_renderer {
display: flex;
align-content: stretch;
.dropdown,
.o_kanban_manage_button_section {
position: inherit;
@@ -29,29 +26,15 @@
}
.o_kanban_quick_create {
box-shadow: $box-shadow;
margin: 0 $o-kanban-record-margin ($o-kanban-record-margin * 2);
.o_form_view {
padding: 0;
.o_group.o_inner_group {
margin: 0;
}
}
.o_kanban_cancel {
color: map-get($grays, "600"); // to make color uniform in community and enterprise
}
&.o_disabled {
pointer-events: none;
opacity: 0.7;
.o_form_view .o_group.o_inner_group {
margin: 0;
}
}
.o_kanban_record {
position: relative;
display: inline-block; // Force the creation of a block formatting context to clear float items
min-width: 150px;
margin: 0 0 -1px;
@@ -68,13 +51,6 @@
width: $o-kanban-color-border-width;
}
.o_kanban_record_details {
display: flex;
flex-direction: column;
justify-content: space-between;
width: 100%;
}
// Inner Sections
.o_kanban_record_top,
.o_kanban_record_body {
@@ -247,7 +223,6 @@
}
.o_dragged {
@extend .shadow;
transform: rotate(-3deg);
transition: transform 0.6s, box-shadow 0.3s;
@@ -461,8 +436,6 @@
// Kanban Grouped Layout
&.o_kanban_grouped {
min-height: 100%;
padding: 0;
background-color: $gray-100;
@include media-breakpoint-down(md) {
min-height: initial;
@@ -471,11 +444,8 @@
scroll-snap-type: x mandatory;
}
.o_kanban_record,
.o_kanban_quick_create {
.o_kanban_record {
width: 100%;
margin-left: 0;
margin-right: 0;
}
&.o_kanban_small_column .o_kanban_group:not(.o_column_folded) {
@@ -485,29 +455,10 @@
// Kanban Grouped Layout - Column default
.o_kanban_group {
flex: 0 0 $o-kanban-default-record-width + 2 * $o-kanban-group-padding;
flex-basis: $o-kanban-default-record-width + 2 * $o-kanban-group-padding;
padding: 0 $o-kanban-group-padding $o-kanban-group-padding $o-kanban-group-padding;
background-color: inherit;
.o_kanban_header > .o_kanban_header_title {
@include o-kanban-header-title;
.o_column_title {
flex: 1 1 auto;
@include o-text-overflow;
font-size: 16px;
font-weight: 500;
}
.o_column_unfold {
display: none;
}
.o_kanban_quick_add i {
@include o-kanban-icon;
margin-left: $o-kanban-inside-hgutter * 2;
}
&:hover .o_kanban_config,
.o_kanban_config.show {
visibility: visible;
@@ -522,9 +473,6 @@
> .dropdown-menu {
cursor: default;
}
i {
@include o-kanban-icon;
}
}
}
}
@@ -545,22 +493,11 @@
}
.o_kanban_header_title {
position: relative;
opacity: 0.5;
.o_column_title {
@include o-kanban-v-title;
}
.o_column_unfold {
@include o-kanban-icon(1);
}
}
> .o_kanban_record,
.o_kanban_quick_add,
.o_kanban_config,
.o_kanban_load_more {
display: none !important;
}
&:hover,
@@ -576,94 +513,42 @@
.o_column_quick_create {
flex: 0 0 $o-kanban-small-record-width + 2 * $o-kanban-group-padding;
.o_quick_create_folded {
cursor: pointer;
padding: 12px 16px;
white-space: nowrap;
font-weight: $font-weight-bold;
@include o-hover-opacity(0.7);
@include o-hover-text-color($text-muted, $body-color);
}
.o_quick_create_unfolded {
margin: $border-width ($o-kanban-inside-hgutter * 0.5) 0;
padding: $o-kanban-inside-vgutter $o-kanban-inside-hgutter;
@include media-breakpoint-down(md) {
margin: 0;
}
.o_kanban_header {
height: 50px;
.o_kanban_examples {
cursor: pointer;
}
input,
input:focus,
input:hover {
font-size: 16px;
background: transparent;
}
}
.o_kanban_muted_record {
background: map-get($grays, "300");
height: 70px;
margin: 10px 0px;
}
}
}
@include media-breakpoint-down(md) {
.o_kanban_group,
.o_column_quick_create {
flex: 1 0 90%; // don't take full width to give a hint of next/previous column
flex-basis: 90%; // don't take full width to give a hint of next/previous column
scroll-snap-align: center;
overflow-y: scroll;
.o_kanban_header {
position: sticky; // keep it visible
top: 0;
z-index: 10; // same as the sticky ControlPanel
z-index: $zindex-sticky;
background-color: inherit;
}
.o_kanban_header_title {
margin-top: 0 !important; // avoid sticky glitch when scrolling
}
}
}
// Kanban UN-grouped Layout
&.o_kanban_ungrouped {
min-height: 100%;
align-content: flex-start;
flex-flow: row wrap;
justify-content: flex-start;
padding: $o-kanban-record-margin ($o-horizontal-padding - $o-kanban-record-margin);
.o_kanban_record {
display: flex;
flex: 1 1 auto;
width: $o-kanban-default-record-width;
margin: ($o-kanban-record-margin * 0.5) $o-kanban-record-margin;
@include media-breakpoint-down(md) {
margin: 0 0 -1px 0;
flex: 1 0 100%;
flex-basis: 100%;
}
&.o_kanban_ghost {
height: 0;
border: none;
min-height: 0 !important; // to prevent view writers to override this height
visibility: hidden;
margin-top: 0;
margin-bottom: 0;
padding: 0;
max-height: 0 !important; // to prevent view writers to override this height
}
}
}
@@ -686,17 +571,6 @@
// ----------------- Set Cover Dialog -----------------
.modal .o_kanban_cover_container .o_kanban_cover_image {
border: 1px solid $border-color;
height: 120px;
width: 120px;
cursor: pointer;
&.o_selected {
border-color: $o-brand-primary;
}
> img {
@include o-position-absolute(0, 0, 0, 0);
max-height: 100%;
}
}
@@ -5,11 +5,11 @@
<Dialog title="'Set a Cover Image'" size="'lg'">
<div t-if="attachments.length" class="o_kanban_cover_container bg-100">
<t t-foreach="attachments" t-as="attachment" t-key="attachment.id">
<div class="o_kanban_cover_image position-relative d-inline-block m-2 bg-white" t-att-class="{
o_selected: state.selectedAttachmentId === attachment.id,
<div class="o_kanban_cover_image position-relative d-inline-block m-2 border bg-white o_cursor_pointer" t-att-class="{
'o_selected border-primary': state.selectedAttachmentId === attachment.id,
}">
<img t-attf-src="/web/image/{{attachment.id}}?unique=1"
class="m-auto mw-100"
class="position-absolute start-0 end-0 top-0 bottom-0 mw-100 mh-100 m-auto"
alt="Attachment"
t-on-click="() => this.selectAttachment(attachment, false)"
t-on-dblclick="() => this.selectAttachment(attachment, true)"
@@ -1,9 +1,4 @@
.o_kanban_dashboard:not(.o_legacy_kanban_view) {
&:not(.o_kanban_grouped) {
// correctly display the no_content_helper in dashboards
flex-flow: row wrap;
}
.o_kanban_record > div {
position: relative;
display: flex;
@@ -46,54 +46,25 @@
// container ghost card in background
.o_kanban_example_background_container {
display: flex;
padding: 0px;
opacity: 0.4;
// content
.o_kanban_example_background {
flex: 1 1 100%;
flex-basis: 100%;
.o_kanban_examples {
.o_kanban_examples_group {
.o_kanban_examples_ghost {
width: 224px;
margin-bottom: 10px;
}
}
.o_kanban_examples .o_kanban_examples_group .o_kanban_examples_ghost {
width: $o-kanban-small-record-width;
}
}
}
// kanban ghost card
.o_kanban_examples {
display: flex;
padding: 0 6px;
.o_kanban_examples .o_kanban_examples_group .o_kanban_examples_ghost {
&.o_collapse {
margin-top: -1px;
}
.o_kanban_examples_group {
flex: 1 1 100%;
margin: 10px;
.o_kanban_examples_ghost {
padding: 5px;
margin-top: -1px;
border: thin solid map-get($grays, '300');
background-color: white;
.o_ghost_content {
height: 12px;
background: map-get($grays, '300');
&.o_ghost_tag {
display: inline-block;
width: 40%;
margin-top: 10px;
}
}
.o_ghost_avatar {
height: 20px;
width: 20px;
margin-top: 6px;
}
}
.o_ghost_avatar {
height: 20px;
width: 20px;
}
}
@@ -221,7 +221,7 @@ export class KanbanRecord extends Component {
getRecordClasses() {
const { archInfo, canResequence, forceGlobalClick, group, record } = this.props;
const classes = ["o_kanban_record"];
const classes = ["o_kanban_record d-flex"];
if (canResequence) {
classes.push("o_record_draggable");
}
@@ -239,6 +239,9 @@ export class KanbanRecord extends Component {
if (record.model.useSampleModel) {
classes.push("o_sample_data_disabled");
}
if (!this.props.list.isGrouped) {
classes.push("flex-grow-1 flex-md-shrink-1 flex-shrink-0");
}
return classes.join(" ");
}
@@ -3,11 +3,11 @@
<t t-name="web.KanbanRecordQuickCreate" owl="1">
<div
class="o_kanban_quick_create"
t-att-class="{ o_disabled: state.disabled }"
class="o_kanban_quick_create shadow"
t-att-class="{ o_disabled: state.disabled, 'w-100 mx-0': props.listIsGrouped }"
t-ref="root"
>
<FormRenderer class="'o_form_view o_xxs_form_view'" record="props.record" archInfo="props.archInfo" />
<FormRenderer class="'o_form_view o_xxs_form_view p-0'" record="props.record" archInfo="props.archInfo" />
<div class="d-flex">
<button class="btn btn-primary o_kanban_add me-1 text_truncate" t-on-click="() => this.validate('add')">
Add
@@ -15,7 +15,7 @@
<button class="btn btn-primary o_kanban_edit me-1 text_truncate" t-on-click="() => this.validate('edit')">
Edit
</button>
<button class="btn btn-secondary o_kanban_cancel ms-auto" t-on-click="() => this.cancel(true)">
<button class="btn btn-secondary o_kanban_cancel ms-auto text-600" t-on-click="() => this.cancel(true)">
<i class="fa fa-trash" />
</button>
</div>
@@ -61,11 +61,11 @@ export class KanbanRenderer extends Component {
if (group) {
dataGroupId = group.dataset.id;
}
element.classList.add("o_dragged");
element.classList.add("o_dragged", "shadow");
},
onGroupEnter: (group) => group.classList.add("o_kanban_hover"),
onGroupLeave: (group) => group.classList.remove("o_kanban_hover"),
onStop: (_group, element) => element.classList.remove("o_dragged"),
onStop: (_group, element) => element.classList.remove("o_dragged", "shadow"),
onDrop: async ({ element, previous, parent }) => {
element.classList.remove("o_record_draggable");
const refId = previous ? previous.dataset.id : null;
@@ -89,9 +89,9 @@ export class KanbanRenderer extends Component {
// Hooks
onStart: (_group, element) => {
dataGroupId = element.dataset.id;
element.classList.add("o_dragged");
element.classList.add("o_dragged", "shadow");
},
onStop: (_group, element) => element.classList.remove("o_dragged"),
onStop: (_group, element) => element.classList.remove("o_dragged", "shadow"),
onDrop: async ({ element, previous }) => {
element.classList.remove("o_group_draggable");
const refId = previous ? previous.dataset.id : null;
@@ -262,6 +262,9 @@ export class KanbanRenderer extends Component {
if (!this.env.isSmall && group.isFolded) {
classes.push("o_column_folded");
}
if (this.canResequenceGroups && group.value && !group.isFolded && !group.hasActiveProgressValue) {
classes.push("bg-100");
}
if (group.progressBars.length) {
classes.push("o_kanban_has_progressbar");
if (!group.isFolded && group.hasActiveProgressValue) {
@@ -2,25 +2,25 @@
<templates xml:space="preserve">
<t t-name="web.KanbanRenderer" owl="1">
<div class="o_kanban_renderer o_renderer"
t-attf-class="o_kanban_{{ props.list.isGrouped ? '' : 'un' }}grouped {{ props.archInfo.className or '' }}"
<div class="o_kanban_renderer o_renderer d-flex"
t-attf-class="{{ props.list.isGrouped ? 'o_kanban_grouped align-content-stretch' : 'o_kanban_ungrouped align-content-start flex-wrap justify-content-start' }} {{ props.archInfo.className or '' }}"
t-ref="root"
>
<t t-foreach="getGroupsOrRecords()" t-as="groupOrRecord" t-key="groupOrRecord.key">
<t t-if="groupOrRecord.group">
<t t-set="group" t-value="groupOrRecord.group" />
<div class="o_kanban_group"
<div class="o_kanban_group flex-shrink-0 flex-grow-1 flex-md-grow-0"
t-att-class="getGroupClasses(group)"
t-att-data-id="(canResequenceRecords or canResequenceGroups) and group.id"
t-on-click="(ev) => this.onGroupClick(group, ev)"
>
<div class="o_kanban_header">
<div class="o_kanban_header_title" t-att="tooltipAttributes(group)">
<span class="o_column_title" t-esc="getGroupName(group)"/>
<div class="o_kanban_header top-0" t-attf-class="{{ !env.isSmall and group.isFolded ? 'pt-3' : 'py-3' }}">
<div class="o_kanban_header_title position-relative d-flex align-items-center lh-lg text-900" t-att="tooltipAttributes(group)">
<span class="o_column_title flex-grow-1 d-inline-block mw-100 text-truncate fs-4 fw-bold align-top" t-att-class="{ 'overflow-visible': !env.isSmall and group.isFolded }" t-esc="getGroupName(group)"/>
<t t-if="env.isSmall or !group.isFolded">
<Dropdown class="'o_kanban_config'" togglerClass="'btn p-0'">
<Dropdown class="'o_kanban_config'" togglerClass="'btn p-0 border-0'">
<t t-set-slot="toggler">
<i class="fa fa-gear" role="img" aria-label="Settings" title="Settings" />
<i class="fa fa-gear fa-stack d-block text-center text-700 small opacity-50 opacity-100-hover cursor-pointer" role="img" aria-label="Settings" title="Settings" />
</t>
<DropdownItem t-if="!env.isSmall" class="{
'o_kanban_toggle_fold': true,
@@ -47,21 +47,21 @@
</DropdownItem>
</t>
</Dropdown>
<span t-if="props.list.canQuickCreate()" class="o_kanban_quick_add" t-on-click="() => this.quickCreate(group)">
<i class="fa fa-plus" role="img" aria-label="Quick add" title="Quick add" />
</span>
<button t-if="props.list.canQuickCreate()" class="o_kanban_quick_add btn p-0 border-0 fs-6 shadow-none" t-on-click="() => this.quickCreate(group)">
<i class="fa fa-plus fa-stack d-block small text-end text-700 opacity-50 opacity-100-hover cursor-pointer" role="img" aria-label="Quick add" title="Quick add" />
</button>
</t>
<span t-else="" class="o_column_unfold">
<button t-else="" class="o_column_unfold btn btn-link d-block mt-0 mt-md-2 p-0 border-0 small text-center text-700 cursor-pointer">
<i class="fa fa-arrows-h" role="img" aria-label="Unfold" title="Unfold" />
</span>
</button>
</div>
<div t-if="(env.isSmall or !group.isFolded) and group.progressBars.length" class="o_kanban_counter">
<div class="o_kanban_counter_progress progress">
<div t-if="(env.isSmall or !group.isFolded) and group.progressBars.length" class="o_kanban_counter position-relative d-flex align-items-center justify-content-between" t-att-class="{ 'opacity-25': !group.count }">
<div class="o_kanban_counter_progress progress w-75 bg-300">
<t t-foreach="group.progressBars" t-as="progressBar" t-key="progressBar.value">
<div t-if="progressBar.count"
role="progressbar"
class="progress-bar o_bar_has_records"
t-att-class="{ 'progress-bar-animated progress-bar-striped': group.progressValue.active === progressBar.value }"
class="progress-bar o_bar_has_records cursor-pointer"
t-att-class="{ 'progress-bar-animated progress-bar-striped': group.progressValue.active === progressBar.value, 'border border-white': !group.isFolded and group.hasActiveProgressValue }"
t-attf-class="bg-{{ progressBar.color }}"
t-attf-style="width: {{ progressBar.count / (group.count or 1) * 100 }}%;"
aria-valuemin="0"
@@ -91,6 +91,7 @@
archInfo="props.list.quickCreateInfo"
onCancel="force => group.list.cancelQuickCreate(force)"
onValidate="mode => this.validateQuickCreate(mode, group)"
listIsGrouped="props.list.isGrouped"
/>
</t>
<t t-else="">
@@ -144,16 +145,16 @@
/>
</t>
<!-- Kanban Example Background -->
<div t-if="props.list.groups.length === 0" class="o_kanban_example_background_container">
<div class="o_kanban_example_background">
<div class="o_kanban_examples">
<div t-foreach="ghostColumns" t-as="column" t-key="column" class="o_kanban_examples_group">
<div t-if="props.list.groups.length === 0" class="o_kanban_example_background_container d-flex opacity-50">
<div class="o_kanban_example_background flex-grow-1">
<div class="o_kanban_examples d-flex p-2">
<div t-foreach="ghostColumns" t-as="column" t-key="column" class="o_kanban_examples_group flex-grow-1 m-3">
<h6><b t-esc="column.name"/></h6>
<div t-foreach="column.cards" t-as="card" t-key="card_index" class="o_kanban_examples_ghost">
<div class="o_ghost_content"/>
<div class="o_ghost_content o_ghost_tag"/>
<div t-foreach="column.cards" t-as="card" t-key="card_index" class="o_kanban_examples_ghost d-flex flex-wrap justify-content-between mb-3 p-2 border bg-white">
<div class="o_ghost_content w-100 pb-3 bg-300"/>
<div class="o_ghost_content o_ghost_tag d-inline-block w-50 mt-3 pb-3 bg-300"/>
<!-- FIXME WOWL example avatar is white on white (also in legacy) -->
<img class="float-end o_ghost_avatar" src="/base/static/img/avatar.png" alt="Avatar"/>
<img class="o_ghost_avatar" src="/base/static/img/avatar.png" alt="Avatar"/>
</div>
</div>
</div>
@@ -162,7 +163,7 @@
</t>
<t t-else="">
<!-- kanban ghost cards are used to properly space last elements. -->
<div t-foreach="[,,,,,,]" t-as="i" t-key="i_index" class="o_kanban_record o_kanban_ghost" />
<div t-foreach="[,,,,,,]" t-as="i" t-key="i_index" class="o_kanban_record o_kanban_ghost flex-grow-1 flex-md-shrink-1 flex-shrink-0 my-0" />
</t>
<t t-if="showNoContentHelper">
<t t-if="props.noContentHelp" t-call="web.ActionHelper">