From 9f81007d8e93a4b8acaef910960fc3ae427e7731 Mon Sep 17 00:00:00 2001
From: Alexander Platov <sas_lord@mail.ru>
Date: Mon, 3 Jul 2023 15:15:48 +0300
Subject: [PATCH] UBER-538: fixed ListView and KanbanView. (#3475)

Signed-off-by: Alexander Platov <sas_lord@mail.ru>
---
 models/lead/src/index.ts                      |  32 +++--
 models/recruit/src/index.ts                   |  11 +-
 packages/kanban/src/components/Kanban.svelte  |   2 +-
 packages/theme/styles/components.scss         |  31 +++--
 packages/ui/src/components/ScrollBox.svelte   |   2 +
 packages/ui/src/components/Scroller.svelte    |   2 +-
 .../calendar/DueDatePresenter.svelte          |   2 +-
 .../src/components/ChannelsDropdown.svelte    |   2 +-
 .../src/components/ContactPresenter.svelte    |   6 +-
 .../src/components/KanbanCard.svelte          |  75 +++++------
 .../src/components/KanbanCard.svelte          | 125 ++++++++++--------
 .../src/components/LabelsPresenter.svelte     |   9 +-
 .../src/components/TagsItemPresenter.svelte   |   4 +-
 .../src/components/state/StateEditor.svelte   |   3 +-
 .../components/state/StateRefPresenter.svelte |   3 +-
 .../src/components/ComponentSelector.svelte   |   3 +
 .../components/ComponentEditor.svelte         |   2 +
 .../components/issues/IssuePresenter.svelte   |  10 +-
 .../src/components/issues/KanbanView.svelte   |  22 +--
 19 files changed, 196 insertions(+), 150 deletions(-)

diff --git a/models/lead/src/index.ts b/models/lead/src/index.ts
index 7ca02be152..9193e336ca 100644
--- a/models/lead/src/index.ts
+++ b/models/lead/src/index.ts
@@ -302,11 +302,14 @@ export function createModel (builder: Builder): void {
       },
       config: [
         { key: '', displayProps: { fixed: 'left', key: 'lead' } },
+        {
+          key: 'state',
+          props: { kind: 'list', size: 'small', shouldShowName: false }
+        },
         {
           key: '',
           presenter: lead.component.TitlePresenter,
           label: lead.string.Title,
-          displayProps: { fixed: 'left', key: 'title' },
           props: { maxWidth: '10rem' }
         },
         {
@@ -314,35 +317,38 @@ export function createModel (builder: Builder): void {
           presenter: contact.component.PersonPresenter,
           label: lead.string.Customer,
           sortingKey: '$lookup.attachedTo.name',
-          displayProps: { fixed: 'left', key: 'talent' },
           props: {
             _class: lead.mixin.Customer,
             inline: true,
             maxWidth: '10rem'
           }
         },
-        { key: 'state', displayProps: { fixed: 'left', key: 'state' } },
         {
           key: '',
           presenter: tracker.component.RelatedIssueSelector,
           label: tracker.string.Relations,
-          displayProps: { fixed: 'left', key: 'issues', optional: true }
+          props: { size: 'small' }
         },
-        { key: 'attachments', displayProps: { key: 'attachments', optional: true } },
-        { key: 'comments', displayProps: { key: 'comments', optional: true } },
+        { key: 'attachments', displayProps: { key: 'attachments', suffix: true } },
+        { key: 'comments', displayProps: { key: 'comments', suffix: true } },
         { key: '', displayProps: { grow: true } },
         {
           key: '$lookup.attachedTo.$lookup.channels',
           label: contact.string.ContactInfo,
           sortingKey: ['$lookup.attachedTo.$lookup.channels.lastMessage', '$lookup.attachedTo.channels'],
-          displayProps: {
-            fixed: 'left',
-            key: 'channels',
-            dividerBefore: true
-          }
+          props: {
+            length: 'full',
+            size: 'small',
+            kind: 'list'
+          },
+          displayProps: { optional: true }
         },
-        { key: 'modifiedOn', displayProps: { key: 'modified', fixed: 'left', dividerBefore: true } },
-        { key: 'assignee', displayProps: { key: 'assignee', fixed: 'right' }, props: { shouldShowLabel: false } }
+        { key: 'modifiedOn', displayProps: { key: 'modified', fixed: 'right', dividerBefore: true } },
+        {
+          key: 'assignee',
+          props: { kind: 'list', shouldShowName: false, avatarSize: 'x-small' },
+          displayProps: { key: 'assignee', fixed: 'right' }
+        }
       ],
       viewOptions: leadViewOptions
     },
diff --git a/models/recruit/src/index.ts b/models/recruit/src/index.ts
index 627f5ab521..86b656baeb 100644
--- a/models/recruit/src/index.ts
+++ b/models/recruit/src/index.ts
@@ -685,8 +685,7 @@ export function createModel (builder: Builder): void {
         { key: '', displayProps: { fixed: 'left', key: 'app' } },
         {
           key: 'state',
-          props: { kind: 'list', size: 'small', shouldShowName: false },
-          displayProps: { excludeByKey: 'state' }
+          props: { kind: 'list', size: 'small', shouldShowName: false }
         },
         {
           key: '$lookup.attachedTo',
@@ -721,14 +720,16 @@ export function createModel (builder: Builder): void {
           sortingKey: ['$lookup.attachedTo.$lookup.channels.lastMessage', '$lookup.attachedTo.channels'],
           props: {
             length: 'full',
-            size: 'inline'
-          }
+            size: 'small',
+            kind: 'list'
+          },
+          displayProps: { optional: true }
         },
         { key: 'modifiedOn', displayProps: { key: 'modified', fixed: 'right', dividerBefore: true } },
         {
           key: 'assignee',
           props: { kind: 'list', shouldShowName: false, avatarSize: 'x-small' },
-          displayProps: { key: 'assignee', fixed: 'right', excludeByKey: 'assignee' }
+          displayProps: { key: 'assignee', fixed: 'right' }
         }
       ],
       options: {
diff --git a/packages/kanban/src/components/Kanban.svelte b/packages/kanban/src/components/Kanban.svelte
index 5e9ce22316..5855d6a2b1 100644
--- a/packages/kanban/src/components/Kanban.svelte
+++ b/packages/kanban/src/components/Kanban.svelte
@@ -366,7 +366,7 @@
   }
   .kanban-content {
     display: flex;
-    padding: 1.5rem;
+    padding: 1.5rem 1.5rem 0.5rem;
     min-width: 0;
   }
 
diff --git a/packages/theme/styles/components.scss b/packages/theme/styles/components.scss
index 71c317354d..54c0cbb3e1 100644
--- a/packages/theme/styles/components.scss
+++ b/packages/theme/styles/components.scss
@@ -901,11 +901,6 @@
       flex-shrink: .5;
       min-width: initial;
     }
-    .label-wrapper {
-      display: flex;
-      align-items: center;
-      min-width: 0;
-    }
     & > *:last-child {
       flex-shrink: 0;
       width: max-content;
@@ -936,8 +931,26 @@
 }
 
 /* Kanban - global style */
-.kanban-container .card-container .card-labels > * { margin: .25rem .25rem 0 0; }
-.kanban-container .card-container .card-labels.labels > *:last-child {
-  flex-shrink: 0;
-  margin-right: 0;
+.kanban-container .card-container .card-labels > *:not(.labels-container),
+.kanban-container .card-container .card-labels.labels .labels-container > * {
+  margin: .25rem .25rem 0 0;
+
+  &:last-child {
+    flex-shrink: 0;
+    margin-right: 0;
+  }
+}
+.kanban-container .card-container .card-labels .datetime-button {
+  padding: 0 0.25rem !important;
+  height: 1.75rem !important;
+  font-size: .8125rem !important;
+}
+.kanban-container .card-container .card-labels .label { font-size: .8125rem !important; }
+
+/* ListView & Kanban */
+.list-container .optional-bar .label-wrapper,
+.kanban-container .card-container .card-labels .label-wrapper {
+  display: flex;
+  align-items: center;
+  min-width: 0;
 }
diff --git a/packages/ui/src/components/ScrollBox.svelte b/packages/ui/src/components/ScrollBox.svelte
index 0ff421bd28..95ba6f0cf3 100644
--- a/packages/ui/src/components/ScrollBox.svelte
+++ b/packages/ui/src/components/ScrollBox.svelte
@@ -14,6 +14,7 @@
 -->
 <script lang="ts">
   import { afterUpdate } from 'svelte'
+  import { closeTooltip } from '..'
 
   export let vertical: boolean = false
   export let stretch: boolean = false
@@ -29,6 +30,7 @@
   })
 
   function setAutoscroll () {
+    closeTooltip()
     autoscroll = div.scrollTop > div.scrollHeight - div.clientHeight - 50
   }
 </script>
diff --git a/packages/ui/src/components/Scroller.svelte b/packages/ui/src/components/Scroller.svelte
index f1bb2efad1..01b94c2fd2 100644
--- a/packages/ui/src/components/Scroller.svelte
+++ b/packages/ui/src/components/Scroller.svelte
@@ -474,7 +474,7 @@
       class="scroll relative flex-shrink"
       style:overflow-x={horizontal ? 'auto' : 'hidden'}
       on:scroll={() => {
-        if ($tooltipstore.label !== undefined) closeTooltip()
+        if ($tooltipstore.label !== undefined || $tooltipstore.component !== undefined) closeTooltip()
       }}
     >
       <div
diff --git a/packages/ui/src/components/calendar/DueDatePresenter.svelte b/packages/ui/src/components/calendar/DueDatePresenter.svelte
index 8695678707..7987c8d832 100644
--- a/packages/ui/src/components/calendar/DueDatePresenter.svelte
+++ b/packages/ui/src/components/calendar/DueDatePresenter.svelte
@@ -27,7 +27,7 @@
   export let editable: boolean = true
   export let shouldIgnoreOverdue: boolean = false
   export let size: ButtonSize = 'medium'
-  export let width: string | undefined = undefined
+  export let width: string | undefined = 'auto'
 
   const today = new Date(new Date(Date.now()).setHours(0, 0, 0, 0))
   $: isOverdue = value !== null && value < today.getTime()
diff --git a/plugins/contact-resources/src/components/ChannelsDropdown.svelte b/plugins/contact-resources/src/components/ChannelsDropdown.svelte
index d71d0012ff..47c81779f6 100644
--- a/plugins/contact-resources/src/components/ChannelsDropdown.svelte
+++ b/plugins/contact-resources/src/components/ChannelsDropdown.svelte
@@ -261,7 +261,7 @@
         id={item.label}
         bind:input={btns[i]}
         icon={item.icon}
-        kind={highlighted.includes(item.provider) ? 'dangerous' : kind}
+        kind={'link-bordered'}
         {size}
         {shape}
         highlight={item.integration || item.notification}
diff --git a/plugins/contact-resources/src/components/ContactPresenter.svelte b/plugins/contact-resources/src/components/ContactPresenter.svelte
index 8babf70a31..18edd6840e 100644
--- a/plugins/contact-resources/src/components/ContactPresenter.svelte
+++ b/plugins/contact-resources/src/components/ContactPresenter.svelte
@@ -21,12 +21,14 @@
 
   import OrganizationPresenter from './OrganizationPresenter.svelte'
   import PersonPresenter from './PersonPresenter.svelte'
+  import { IconSize } from '@hcengineering/ui'
 
   export let value: Contact
   export let inline: boolean = false
   export let disabled: boolean = false
   export let accent: boolean = false
   export let maxWidth = ''
+  export let avatarSize: IconSize = 'x-small'
 
   function isPerson (value: Contact): boolean {
     const client = getClient()
@@ -43,9 +45,9 @@
 </script>
 
 {#if isEmployee(value)}
-  <EmployeePresenter {disabled} value={toEmployee(value)} {inline} {accent} />
+  <EmployeePresenter {disabled} value={toEmployee(value)} {inline} {accent} {avatarSize} />
 {:else if isPerson(value)}
-  <PersonPresenter {disabled} {value} {inline} {accent} />
+  <PersonPresenter {disabled} {value} {inline} {accent} {avatarSize} />
 {:else}
   <OrganizationPresenter value={toOrg(value)} {inline} {accent} {maxWidth} />
 {/if}
diff --git a/plugins/lead-resources/src/components/KanbanCard.svelte b/plugins/lead-resources/src/components/KanbanCard.svelte
index 0de48c2695..88d02f3400 100644
--- a/plugins/lead-resources/src/components/KanbanCard.svelte
+++ b/plugins/lead-resources/src/components/KanbanCard.svelte
@@ -44,11 +44,10 @@
   }
 </script>
 
-<div class="flex-col pt-2 pb-2 pr-4 pl-4">
-  <div class="flex-between mb-4">
-    <div class="flex-col">
-      <div class="fs-title cursor-pointer" on:click={showLead}>{object.title}</div>
-    </div>
+<div class="flex-col pt-3 pb-3 pr-4 pl-4">
+  <div class="flex-between mb-3">
+    <!-- svelte-ignore a11y-click-events-have-key-events -->
+    <div class="fs-title cursor-pointer" on:click={showLead}>{object.title}</div>
     <div class="flex-row-center">
       <div class="mr-2">
         <Component is={notification.component.NotificationPresenter} props={{ value: object }} />
@@ -63,42 +62,44 @@
       />
     </div>
   </div>
-  <div class="flex-col">
-    <div class="flex-between">
-      {#if enabledConfig(config, 'attachedTo') && object.$lookup?.attachedTo}
-        <ContactPresenter value={object.$lookup.attachedTo} />
-      {/if}
-      <div class="flex-row-center gap-3">
-        {#if enabledConfig(config, 'attachments') && (object.attachments ?? 0) > 0}
-          <AttachmentsPresenter value={object.attachments} {object} />
-        {/if}
-        {#if enabledConfig(config, 'comments') && (object.comments ?? 0) > 0}
-          <CommentsPresenter value={object.comments} {object} />
-        {/if}
-      </div>
+  <div class="flex-between mb-2">
+    {#if enabledConfig(config, 'attachedTo') && object.$lookup?.attachedTo}
+      <ContactPresenter value={object.$lookup.attachedTo} avatarSize={'small'} />
+    {/if}
+  </div>
+  {#if enabledConfig(config, 'dueDate')}
+    <div class="card-labels labels mb-2">
+      <DueDatePresenter
+        size={'small'}
+        kind={'link-bordered'}
+        width={'fit-content'}
+        value={object.dueDate}
+        shouldRender={object.dueDate !== null && object.dueDate !== undefined}
+        shouldIgnoreOverdue={object.doneState !== null}
+        onChange={async (e) => {
+          await client.update(object, { dueDate: e })
+        }}
+      />
     </div>
-    <div class="flex-row-center flex-between mt-2">
+  {/if}
+  <div class="flex-between">
+    <div class="flex-row-center gap-3 reverse mr-4">
       <LeadPresenter value={object} />
-      {#if enabledConfig(config, 'dueDate')}
-        <DueDatePresenter
-          size={'small'}
-          value={object.dueDate}
-          shouldRender={object.dueDate !== null && object.dueDate !== undefined}
-          shouldIgnoreOverdue={object.doneState !== null}
-          onChange={async (e) => {
-            await client.update(object, { dueDate: e })
-          }}
-        />
+      {#if enabledConfig(config, 'attachments') && (object.attachments ?? 0) > 0}
+        <AttachmentsPresenter value={object.attachments} {object} />
       {/if}
-      {#if enabledConfig(config, 'assignee')}
-        <AssigneePresenter
-          value={object.assignee}
-          issueId={object._id}
-          defaultClass={contact.class.Employee}
-          currentSpace={object.space}
-          placeholderLabel={assigneeAttribute.label}
-        />
+      {#if enabledConfig(config, 'comments') && (object.comments ?? 0) > 0}
+        <CommentsPresenter value={object.comments} {object} />
       {/if}
     </div>
+    {#if enabledConfig(config, 'assignee')}
+      <AssigneePresenter
+        value={object.assignee}
+        issueId={object._id}
+        defaultClass={contact.class.Employee}
+        currentSpace={object.space}
+        placeholderLabel={assigneeAttribute.label}
+      />
+    {/if}
   </div>
 </div>
diff --git a/plugins/recruit-resources/src/components/KanbanCard.svelte b/plugins/recruit-resources/src/components/KanbanCard.svelte
index 9a32e5a56e..64b6b00262 100644
--- a/plugins/recruit-resources/src/components/KanbanCard.svelte
+++ b/plugins/recruit-resources/src/components/KanbanCard.svelte
@@ -48,9 +48,9 @@
 </script>
 
 <!-- svelte-ignore a11y-click-events-have-key-events -->
-<div class="flex-col pt-2 pb-2 pr-4 pl-4 cursor-pointer" on:click={showCandidate}>
+<div class="flex-col pt-3 pb-3 pr-4 pl-4" on:click={showCandidate}>
   {#if enabledConfig(config, 'space') || enabledConfig(config, 'company')}
-    <div class="p-1 flex-between gap-2">
+    <div class="flex-between mb-3">
       {#if enabledConfig(config, 'space')}
         <ObjectPresenter _class={recruit.class.Vacancy} objectId={object.space} value={object.$lookup?.space} />
       {/if}
@@ -59,7 +59,7 @@
       {/if}
     </div>
   {/if}
-  <div class="flex-between mb-3">
+  <div class="flex-between mb-1">
     <div class="flex-row-center">
       <Avatar avatar={object.$lookup?.attachedTo?.avatar} size={'medium'} />
       <div class="flex-grow flex-col min-w-0 ml-2">
@@ -71,63 +71,69 @@
         {/if}
       </div>
     </div>
-    <div class="tool mr-1 flex-row-center">
+    <div class="tool flex-row-center">
       {#if !dragged}
         <div class="mr-2">
           <Component showLoading={false} is={notification.component.NotificationPresenter} props={{ value: object }} />
         </div>
       {/if}
     </div>
-    {#if channels && channels.length > 0 && enabledConfig(config, 'channels')}
-      <div class="tool mr-1 flex-row-center">
-        <div class="step-lr75">
-          <Component
-            showLoading={false}
-            is={contact.component.ChannelsPresenter}
-            props={{ value: channels, object: object.$lookup?.attachedTo, length: 'tiny', size: 'inline' }}
-          />
-        </div>
-      </div>
+  </div>
+  {#if channels && channels.length > 0 && enabledConfig(config, 'channels')}
+    <div class="card-labels labels mb-2">
+      <Component
+        showLoading={false}
+        is={contact.component.ChannelsPresenter}
+        props={{ value: channels, object: object.$lookup?.attachedTo, length: 'full', size: 'inline', kind: 'list' }}
+      />
+    </div>
+  {/if}
+  <div class="card-labels mb-2">
+    {#if groupByKey !== 'state' && enabledConfig(config, 'state')}
+      <StateRefPresenter
+        size={'small'}
+        kind={'link-bordered'}
+        shrink={1}
+        value={object.state}
+        onChange={(state) => {
+          client.update(object, { state })
+        }}
+      />
+    {/if}
+    <Component showLoading={false} is={tracker.component.RelatedIssueSelector} props={{ object, size: 'small' }} />
+    {#if enabledConfig(config, 'dueDate')}
+      <DueDatePresenter
+        size={'small'}
+        kind={'link-bordered'}
+        value={object.dueDate}
+        shouldRender={object.dueDate !== null && object.dueDate !== undefined}
+        shouldIgnoreOverdue={object.doneState !== null}
+        onChange={async (e) => {
+          await client.update(object, { dueDate: e })
+        }}
+      />
     {/if}
   </div>
   <div class="flex-between">
-    <div class="flex-row-center">
-      <div class="sm-tool-icon step-lr75">
-        {#if enabledConfig(config, '')}
-          <div class="mr-2">
-            <ApplicationPresenter value={object} inline />
-          </div>
-        {/if}
-        <Component showLoading={false} is={tracker.component.RelatedIssueSelector} props={{ object }} />
-      </div>
-      {#if enabledConfig(config, 'dueDate')}
-        <DueDatePresenter
-          size={'small'}
-          value={object.dueDate}
-          shouldRender={object.dueDate !== null && object.dueDate !== undefined}
-          shouldIgnoreOverdue={object.doneState !== null}
-          onChange={async (e) => {
-            await client.update(object, { dueDate: e })
-          }}
-        />
+    <div class="flex-row-center gap-3 reverse mr-4">
+      {#if enabledConfig(config, '')}
+        <ApplicationPresenter value={object} inline />
       {/if}
-      <div class="flex-row-center gap-3">
-        {#if (object.attachments ?? 0) > 0 && enabledConfig(config, 'attachments')}
-          <AttachmentsPresenter value={object.attachments} {object} />
+      {#if (object.attachments ?? 0) > 0 && enabledConfig(config, 'attachments')}
+        <AttachmentsPresenter value={object.attachments} {object} />
+      {/if}
+      {#if enabledConfig(config, 'comments')}
+        {#if (object.comments ?? 0) > 0}
+          <CommentsPresenter value={object.comments} {object} />
         {/if}
-        {#if enabledConfig(config, 'comments')}
-          {#if (object.comments ?? 0) > 0}
-            <CommentsPresenter value={object.comments} {object} />
-          {/if}
-          {#if object.$lookup?.attachedTo !== undefined && (object.$lookup.attachedTo.comments ?? 0) > 0}
-            <CommentsPresenter
-              value={object.$lookup?.attachedTo?.comments}
-              object={object.$lookup?.attachedTo}
-              withInput={false}
-            />
-          {/if}
+        {#if object.$lookup?.attachedTo !== undefined && (object.$lookup.attachedTo.comments ?? 0) > 0}
+          <CommentsPresenter
+            value={object.$lookup?.attachedTo?.comments}
+            object={object.$lookup?.attachedTo}
+            withInput={false}
+          />
         {/if}
-      </div>
+      {/if}
     </div>
     {#if enabledConfig(config, 'assignee')}
       <AssigneePresenter
@@ -139,13 +145,18 @@
       />
     {/if}
   </div>
-  {#if groupByKey !== 'state' && enabledConfig(config, 'state')}
-    <StateRefPresenter
-      size={'small'}
-      value={object.state}
-      onChange={(state) => {
-        client.update(object, { state })
-      }}
-    />
-  {/if}
 </div>
+
+<style lang="scss">
+  .card-labels {
+    display: flex;
+    flex-wrap: nowrap;
+    min-width: 0;
+
+    &.labels {
+      overflow: hidden;
+      flex-shrink: 1;
+      border-radius: 0.5rem;
+    }
+  }
+</style>
diff --git a/plugins/tags-resources/src/components/LabelsPresenter.svelte b/plugins/tags-resources/src/components/LabelsPresenter.svelte
index 9a39bce59b..06fd62ed7c 100644
--- a/plugins/tags-resources/src/components/LabelsPresenter.svelte
+++ b/plugins/tags-resources/src/components/LabelsPresenter.svelte
@@ -58,7 +58,7 @@
       class="label-box no-shrink"
       use:tooltip={{
         component: TagsItemPresenter,
-        props: { value: items, kind: 'list' }
+        props: { value: items, kind: 'link' }
       }}
     >
       <TagsReferencePresenter {items} {kind} />
@@ -99,7 +99,7 @@
     overflow: hidden;
     display: flex;
     align-items: center;
-    // flex-shrink: 0;
+    flex-shrink: 1;
     min-width: 0;
     border-radius: 0.25rem;
   }
@@ -107,15 +107,10 @@
   .label-box {
     display: flex;
     align-items: center;
-    // flex-shrink: 10;
     width: auto;
     min-width: 0;
     border-radius: 0.25rem;
     transition: box-shadow 0.15s ease-in-out;
-
-    // &:not(.no-shrink):last-child {
-    //   flex-shrink: 0;
-    // }
   }
   .wrap-short:not(:last-child) {
     margin-right: 0.375rem;
diff --git a/plugins/tags-resources/src/components/TagsItemPresenter.svelte b/plugins/tags-resources/src/components/TagsItemPresenter.svelte
index 44f25cee12..88452b58c6 100644
--- a/plugins/tags-resources/src/components/TagsItemPresenter.svelte
+++ b/plugins/tags-resources/src/components/TagsItemPresenter.svelte
@@ -18,12 +18,12 @@
   import TagItem from './TagItem.svelte'
 
   export let value: TagReference[] | TagReference
-  export let kind: 'tag' | 'list' = 'tag'
+  export let kind: 'tag' | 'list' | 'link' = 'tag'
 
   $: values = Array.isArray(value) ? value : [value]
 </script>
 
-{#if kind === 'list'}
+{#if kind === 'list' || kind === 'link'}
   <div class="flex-center flex-wrap">
     {#each values as v}
       <div class="m-0-5">
diff --git a/plugins/task-resources/src/components/state/StateEditor.svelte b/plugins/task-resources/src/components/state/StateEditor.svelte
index 6b2182641f..2391652d4a 100644
--- a/plugins/task-resources/src/components/state/StateEditor.svelte
+++ b/plugins/task-resources/src/components/state/StateEditor.svelte
@@ -30,6 +30,7 @@
   export let width: string = 'min-content'
   export let justify: 'left' | 'center' = 'center'
   export let shouldShowName: boolean = true
+  export let shrink: number = 0
 
   let state: State
   let opened: boolean = false
@@ -60,7 +61,7 @@
 {#if kind === 'list' || kind === 'list-header'}
   <StatePresenter value={state} {shouldShowName} shouldShowTooltip on:click={handleClick} />
 {:else}
-  <Button {kind} {size} {width} {justify} on:click={handleClick}>
+  <Button {kind} {size} {width} {justify} {shrink} on:click={handleClick}>
     <svelte:fragment slot="content">
       {#if state}
         <div class="pointer-events-none clear-mins">
diff --git a/plugins/task-resources/src/components/state/StateRefPresenter.svelte b/plugins/task-resources/src/components/state/StateRefPresenter.svelte
index 46ad9852d5..f45a18817b 100644
--- a/plugins/task-resources/src/components/state/StateRefPresenter.svelte
+++ b/plugins/task-resources/src/components/state/StateRefPresenter.svelte
@@ -26,13 +26,14 @@
   export let kind: ButtonKind = 'link'
   export let size: ButtonSize = 'medium'
   export let shouldShowName: boolean = true
+  export let shrink: number = 0
 
   $: state = $statusStore.get(typeof value === 'string' ? value : (value?.values?.[0]?._id as Ref<Status>))
 </script>
 
 {#if value}
   {#if onChange !== undefined && state !== undefined}
-    <StateEditor value={state._id} space={state.space} {onChange} {kind} {size} {shouldShowName} />
+    <StateEditor value={state._id} space={state.space} {onChange} {kind} {size} {shouldShowName} {shrink} />
   {:else}
     <StatePresenter value={state} {shouldShowName} on:accent-color />
   {/if}
diff --git a/plugins/tracker-resources/src/components/ComponentSelector.svelte b/plugins/tracker-resources/src/components/ComponentSelector.svelte
index dadc749b8c..b8756f3377 100644
--- a/plugins/tracker-resources/src/components/ComponentSelector.svelte
+++ b/plugins/tracker-resources/src/components/ComponentSelector.svelte
@@ -34,6 +34,7 @@
   export let onlyIcon: boolean = false
   export let enlargedText: boolean = false
   export let short: boolean = false
+  export let shrink: number = 0
   export let focusIndex: number | undefined = undefined
   export let space: Ref<Project> | undefined = undefined
 
@@ -110,6 +111,7 @@
     disabled={!isEditable}
     {loading}
     {short}
+    {shrink}
     on:click={handleComponentEditorOpened}
   />
 {:else}
@@ -125,6 +127,7 @@
     {loading}
     notSelected={!value}
     {short}
+    {shrink}
     on:click={handleComponentEditorOpened}
   >
     <svelte:fragment slot="content">
diff --git a/plugins/tracker-resources/src/components/components/ComponentEditor.svelte b/plugins/tracker-resources/src/components/components/ComponentEditor.svelte
index df4c11f0d6..91b3dc106d 100644
--- a/plugins/tracker-resources/src/components/components/ComponentEditor.svelte
+++ b/plugins/tracker-resources/src/components/components/ComponentEditor.svelte
@@ -37,6 +37,7 @@
   export let groupBy: string | undefined = undefined
   export let enlargedText = false
   export let compression: boolean = false
+  export let shrink: number = 0
   export let space: Ref<Project> | undefined = undefined
 
   const client = getClient()
@@ -72,6 +73,7 @@
       {popupPlaceholder}
       {onlyIcon}
       {enlargedText}
+      {shrink}
       value={value.component}
       short
       onChange={handleComponentIdChanged}
diff --git a/plugins/tracker-resources/src/components/issues/IssuePresenter.svelte b/plugins/tracker-resources/src/components/issues/IssuePresenter.svelte
index 0dfceff3ed..09f6918362 100644
--- a/plugins/tracker-resources/src/components/issues/IssuePresenter.svelte
+++ b/plugins/tracker-resources/src/components/issues/IssuePresenter.svelte
@@ -47,7 +47,15 @@
 </script>
 
 {#if value}
-  <DocNavLink object={value} {onClick} {disabled} {noUnderline} {inline} component={tracker.component.EditIssue}>
+  <DocNavLink
+    object={value}
+    {onClick}
+    {disabled}
+    {noUnderline}
+    {inline}
+    component={tracker.component.EditIssue}
+    shrink={0}
+  >
     <span class="issuePresenterRoot" class:inline class:list={kind === 'list'}>
       {#if !inline && shouldShowAvatar}
         <div class="icon" use:tooltip={{ label: tracker.string.Issue }}>
diff --git a/plugins/tracker-resources/src/components/issues/KanbanView.svelte b/plugins/tracker-resources/src/components/issues/KanbanView.svelte
index 24f1b9540d..98c6815450 100644
--- a/plugins/tracker-resources/src/components/issues/KanbanView.svelte
+++ b/plugins/tracker-resources/src/components/issues/KanbanView.svelte
@@ -43,8 +43,7 @@
     Loading,
     showPanel,
     showPopup,
-    themeStore,
-    tooltip
+    themeStore
   } from '@hcengineering/ui'
   import {
     AttributeModel,
@@ -389,7 +388,7 @@
                 kind={'link-bordered'}
                 size={'small'}
                 justify={'center'}
-                width={''}
+                shrink={1}
                 bind:onlyIcon={fullFilled[issueId]}
               />
             {/if}
@@ -398,16 +397,16 @@
             {/if}
           </div>
           {#if enabledConfig(config, 'labels')}
-            <div
-              class="card-labels labels"
-              use:tooltip={{
-                component: fullFilled[issueId] ? tags.component.LabelsPresenter : undefined,
-                props: { object: issue, kind: 'full' }
-              }}
-            >
+            <div class="card-labels labels">
               <Component
                 is={tags.component.LabelsPresenter}
-                props={{ value: issue.labels, object: issue, ckeckFilled: fullFilled[issueId], kind: 'kanban' }}
+                props={{
+                  value: issue.labels,
+                  object: issue,
+                  ckeckFilled: fullFilled[issueId],
+                  kind: 'link',
+                  compression: true
+                }}
                 on:change={(res) => {
                   if (res.detail.full) fullFilled[issueId] = true
                 }}
@@ -487,6 +486,7 @@
 
       &.labels {
         overflow: hidden;
+        flex-shrink: 1;
         margin: 0 1rem;
         width: calc(100% - 2rem);
         border-radius: 0 0.24rem 0.24rem 0;