Removed full-size panel mode. Integrate views for channels provider. (#1575)

Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
Alexander Platov 2022-04-28 12:53:35 +03:00 committed by GitHub
parent 64cbfdb7e8
commit bde8549e5d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 384 additions and 316 deletions

View File

@ -14,43 +14,30 @@
// limitations under the License.
-->
<script lang="ts">
import { createEventDispatcher } from 'svelte'
import activity from '@anticrm/activity'
import calendar from '@anticrm/calendar'
import type { Doc } from '@anticrm/core'
import notification from '@anticrm/notification'
import type { Asset } from '@anticrm/platform'
import { Button, AnyComponent, AnySvelteComponent, Component, IconExpand, Panel, Scroller } from '@anticrm/ui'
import { PopupAlignment } from '@anticrm/ui'
import { AnyComponent, AnySvelteComponent, Component, Panel } from '@anticrm/ui'
export let title: string | undefined = undefined
export let subtitle: string | undefined = undefined
export let icon: Asset | AnySvelteComponent | undefined = undefined
export let fullSize: boolean = true
export let showHeader: boolean = true
export let rightSection: AnyComponent | undefined = undefined
export let object: Doc
export let position: PopupAlignment | undefined = undefined
export let panelWidth: number = 0
export let innerWidth: number = 0
export let isSubtitle: boolean = false
export let isProperties: boolean = false
const dispatch = createEventDispatcher()
$: allowFullSize = panelWidth > 1200 && (position === 'full' || position === 'content')
$: isFullSize = allowFullSize && fullSize
const resizePanel = () => {
isFullSize = !isFullSize
}
</script>
<Panel
{title}
{subtitle}
{icon}
rightSection={isFullSize}
rightSection={rightSection !== undefined}
{showHeader}
bind:panelWidth
bind:innerWidth
@ -69,31 +56,12 @@
</svelte:fragment>
<svelte:fragment slot="commands">
<div class="buttons-group xsmall-gap">
<slot name="actions" />
<Component is={calendar.component.DocReminder} props={{ value: object, title }} />
<Component is={notification.component.LastViewEditor} props={{ value: object }} />
</div>
<slot name="actions" />
</svelte:fragment>
<svelte:fragment slot="rightSection">
{#if isFullSize}
<div class="ad-section-50">
<Component is={rightSection ?? activity.component.Activity} props={{ object, fullSize: isFullSize }} />
</div>
{/if}
</svelte:fragment>
<svelte:fragment slot="actions">
{#if allowFullSize}
<Button icon={IconExpand} size={'medium'} kind={'transparent'} on:click={resizePanel} />
{/if}
</svelte:fragment>
{#if isFullSize}
<Scroller correctPadding={40}>
<div class="p-10 clear-mins"><slot /></div>
</Scroller>
{:else}
<Component is={activity.component.Activity} props={{ object, fullSize: isFullSize }}>
<Component is={rightSection ?? activity.component.Activity} props={{ object, integrate: true }}>
<slot />
</Component>
{/if}
</Panel>

View File

@ -61,6 +61,9 @@
--accent-bg-color: #27282b;
--accent-shadow: rgb(0 0 0 / 10%) 0px 2px 4px;
--highlight-select: #8a8f9810;
--highlight-hover: #8a8f9820;
--dark-color: #62666d;
--content-color: #8a8f98;
--accent-color: #d7d8db;
@ -198,6 +201,9 @@
--accent-bg-color: #f8f9fb; // HZ
--accent-shadow: rgb(0 0 0 / 10%) 0px 2px 4px; // Dark
--highlight-select: #3c414910;
--highlight-hover: #3c414920;
--dark-color: #90959d;
--content-color: #3c4149;
--accent-color: #282a30;

View File

@ -343,6 +343,7 @@ p:last-child { margin-block-end: 0; }
.mx-1 { margin: 0 .25rem; }
.mx-2 { margin: 0 .5rem; }
.mx-3 { margin: 0 .75rem; }
.mx-10 { margin: 0 2.5rem; }
.mx-auto { margin: 0 auto; }
.my-4 { margin: 1rem 0; }
@ -593,6 +594,7 @@ a.no-line {
/* Backgrounds & Colors */
.background-body-color { background-color: var(--body-color); }
.background-accent-bg-color { background-color: var(--accent-bg-color); }
.background-highlight-select { background-color: var(--highlight-select); }
.background-theme-content-accent { background-color: var(--theme-content-accent-color); }
.background-theme-bg-color { background-color: var(--theme-bg-color); }
@ -624,3 +626,4 @@ a.no-line {
.border-button-enabled { border: 1px solid var(--theme-button-border-enabled); }
.bottom-divider { border-bottom: 1px solid var(--divider-color); }
.bottom-highlight-select { border-bottom: 1px solid var(--highlight-select); }

View File

@ -26,6 +26,7 @@
min-width: var(--app-panel-width);
width: var(--app-panel-width);
height: 100%;
background-color: var(--board-bg-color);
}
.antiPanel-navigator,
.antiPanel-component {
@ -53,7 +54,10 @@
z-index: 450;
}
}
.antiPanel-component:not(.aside) { flex-grow: 1; }
.antiPanel-component:not(.aside) {
flex-grow: 1;
background-color: var(--board-bg-color);
}
.antiPanel-component.aside {
min-width: 30rem;
width: 30rem;

View File

@ -49,74 +49,74 @@
&.divide {
border-bottom: 1px solid var(--divider-color);
}
}
.ac-header__wrap-description,
.ac-header__wrap-title {
display: flex;
flex-wrap: nowrap;
min-width: 0;
cursor: default;
}
.ac-header__wrap-description {
flex-direction: column;
flex-grow: 1;
}
.ac-header__wrap-title {
align-items: center;
}
.ac-header__wrap-description,
.ac-header__wrap-title {
display: flex;
flex-wrap: nowrap;
min-width: 0;
cursor: default;
}
.ac-header__wrap-description {
flex-direction: column;
flex-grow: 1;
}
.ac-header__wrap-title {
align-items: center;
}
.ac-header__icon {
margin-right: 0.5rem;
color: var(--theme-content-color);
}
.ac-header__title {
min-width: 0;
font-weight: 500;
font-size: 1rem;
.ac-header__icon {
margin-right: 0.5rem;
color: var(--theme-content-color);
}
.ac-header__title {
min-width: 0;
font-weight: 500;
font-size: 1rem;
color: var(--theme-caption-color);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
user-select: none;
}
.ac-header__description {
min-width: 0;
font-size: 0.75rem;
color: var(--theme-content-dark-color);
overflow: hidden;
visibility: visible;
display: -webkit-box;
/* autoprefixer: ignore next */
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
line-clamp: 2;
user-select: none;
}
.ac-header__icon-button {
display: flex;
justify-content: center;
align-items: center;
width: 2rem;
height: 2rem;
color: var(--theme-content-trans-color);
background-color: transparent;
border-radius: .25rem;
cursor: pointer;
&:hover {
color: var(--theme-caption-color);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
user-select: none;
}
.ac-header__description {
min-width: 0;
font-size: 0.75rem;
color: var(--theme-content-dark-color);
overflow: hidden;
visibility: visible;
display: -webkit-box;
/* autoprefixer: ignore next */
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
line-clamp: 2;
user-select: none;
}
.ac-header__icon-button {
display: flex;
justify-content: center;
align-items: center;
width: 2rem;
height: 2rem;
color: var(--theme-content-trans-color);
background-color: transparent;
border-radius: .25rem;
cursor: pointer;
&.selected {
color: var(--theme-content-accent-color);
background-color: var(--menu-bg-select);
cursor: default;
&:hover {
color: var(--theme-caption-color);
}
&.selected {
color: var(--theme-content-accent-color);
background-color: var(--menu-bg-select);
cursor: default;
&:hover {
color: var(--theme-caption-color);
}
}
}
}
@ -412,8 +412,8 @@
}
&.highlightRows .antiTable-body__row {
&.checking { background-color: var(--theme-table-bg-hover); }
&.selected { background-color: var(--menu-bg-select); }
&.checking { background-color: var(--highlight-select); } // --theme-table-bg-hover
&.selected { background-color: var(--highlight-hover); } // --menu-bg-select
}
}

View File

@ -129,7 +129,11 @@
transition: color .15s;
pointer-events: none;
}
&.highlight { box-shadow: inset 0 0 0 1px var(--primary-bg-color); }
&.highlight {
box-shadow: inset 0 0 1px 1px var(--primary-bg-color);
&:hover { box-shadow: inset 0 0 1px 1px var(--primary-bg-hover); }
}
&:hover {
color: var(--accent-color);
transition-duration: 0;

View File

@ -64,7 +64,7 @@
{#if subtitle}<span class="ac-header__description">{subtitle}</span>{/if}
</div>
</div>
<div class="buttons-group xsmall-gap mr-4">
<div class="buttons-group xsmall-gap">
<slot name="commands" />
<slot name="actions" />
</div>
@ -148,17 +148,18 @@
flex-shrink: 0;
min-width: 20rem;
width: 20rem;
border-left: 1px solid var(--divider-color);
// background-color: var(--board-card-bg-color);
&::before {
position: absolute;
content: '';
top: 1.5rem;
bottom: 1.5rem;
left: 0;
width: 1px;
background-color: var(--divider-color);
}
// &::before {
// position: absolute;
// content: '';
// top: 1.5rem;
// bottom: 1.5rem;
// left: 0;
// width: 1px;
// background-color: var(--divider-color);
// }
}
}
</style>

View File

@ -119,7 +119,7 @@
position: fixed;
background-color: transparent;
&.bg { background-color: var(--body-color); }
&.bg { background-color: var(--board-bg-color); }
.panel-container {
padding: .5rem;
width: 100%;

View File

@ -19,6 +19,7 @@
export let padding: boolean = false
export let autoscroll: boolean = false
export let correctPadding: number = 0
export let bottomStart: boolean = false
let mask: 'top' | 'bottom' | 'both' | 'none' = 'bottom'
@ -38,6 +39,7 @@
let visibleEl: number | undefined = undefined
let belowContent: number | undefined = undefined
let scrolling: boolean = false
let firstScroll: boolean = autoscroll
const checkBack = (): void => {
if (divBox) {
@ -149,6 +151,7 @@
divBar.style.top = procTop * (divScroll.clientHeight - 4) + 2 + 'px'
if (mask === 'none') divBar.style.visibility = 'hidden'
else divBar.style.visibility = 'visible'
if (divScroll.clientHeight >= divScroll.scrollHeight) divBar.style.visibility = 'hidden'
}
}
@ -205,8 +208,12 @@
let observer = new IntersectionObserver(() => checkFade(), { root: null, threshold: .1 })
$: if (autoscroll && belowContent && belowContent <= 5) scrolling = true
$: if (scrolling && belowContent && belowContent > 5)
$: if (firstScroll && divScroll && divScroll.clientHeight !== divScroll.scrollHeight) {
divScroll.scrollTop = divScroll.scrollHeight - divScroll.clientHeight
firstScroll = false
}
$: if (autoscroll && belowContent && belowContent <= 50) scrolling = true
$: if (scrolling && belowContent && belowContent > 50)
divScroll.scrollTop = divScroll.scrollHeight - divScroll.clientHeight
onMount(() => {
@ -223,6 +230,7 @@
if (divScroll && divBox) {
const tempEl = divBox.querySelector('*') as HTMLElement
if (tempEl) observer.observe(tempEl)
if (scrolling) divScroll.scrollTop = divScroll.scrollHeight - divScroll.clientHeight
checkFade()
clearTHead()
findTHeaders()
@ -239,7 +247,7 @@
</script>
<svelte:window on:resize={_resize} />
<div class="scroller-container">
<div class="scroller-container" class:bottomStart>
<div
bind:this={divScroll}
bind:clientWidth={divWidth}
@ -290,6 +298,14 @@
flex-direction: column;
height: 100%;
}
.scroller-container.bottomStart {
justify-content: flex-end;
.scroll {
flex-grow: 0;
height: min-content;
.box { height: min-content; }
}
}
.track {
visibility: hidden;

View File

@ -23,7 +23,7 @@
import TxView from './TxView.svelte'
export let object: Doc
export let fullSize: boolean = false
export let integrate: boolean = false
export let showCommenInput: boolean = true
export let transparent: boolean = false
@ -55,7 +55,7 @@
</script>
{#if fullSize || transparent}
{#if !integrate || transparent}
{#if transparent !== undefined && !transparent}
<div class="ac-header short mirror-tool highlight">
<div class="ac-header__wrap-title">
@ -86,11 +86,11 @@
{/if}
</div>
{:else}
<Scroller autoscroll>
<div class="p-10">
<Scroller>
<div class="p-10 bottom-highlight-select">
<slot />
</div>
<div class="ac-header short mirror-tool">
<div class="ac-header short mirror-tool mt-2">
<div class="ac-header__wrap-title">
<div class="flex-center icon"><IconActivity size={'small'} /></div>
<span class="ac-header__title"><Label label={activity.string.Activity} /></span>

View File

@ -16,22 +16,19 @@
<script lang="ts">
import type { Card } from '@anticrm/board'
import { Class, Ref } from '@anticrm/core'
import { Panel } from '@anticrm/panel'
import { getResource } from '@anticrm/platform'
import { createQuery, getClient } from '@anticrm/presentation'
import type { State } from '@anticrm/task'
import task from '@anticrm/task'
import { StyledTextBox } from '@anticrm/text-editor'
import type { AnyComponent } from '@anticrm/ui'
import { EditBox, Icon, Label, Scroller } from '@anticrm/ui'
import { Panel } from '@anticrm/panel'
import { createEventDispatcher, onMount } from 'svelte'
import { EditBox, Icon, Label } from '@anticrm/ui'
import { UpDownNavigator } from '@anticrm/view-resources'
import { createEventDispatcher, onMount } from 'svelte'
import board from '../plugin'
import { getCardActions } from '../utils/CardActionUtils'
import { updateCard } from '../utils/CardUtils'
import CardActions from './editor/CardActions.svelte'
import CardActivity from './editor/CardActivity.svelte'
import CardAttachments from './editor/CardAttachments.svelte'
import CardDetails from './editor/CardDetails.svelte'
@ -76,8 +73,6 @@
dispatch('open', { ignoreKeys: ['comments', 'number', 'title'] })
})
let fullSize: boolean = false
let rightSection: AnyComponent | undefined = undefined
</script>
{#if object !== undefined}
@ -85,9 +80,6 @@
icon={board.icon.Card}
title={object?.title}
{object}
{rightSection}
{fullSize}
position={'content'}
on:close={() => dispatch('close')}
>
<svelte:fragment slot="navigate-actions">

View File

@ -1,11 +1,11 @@
<script lang="ts">
import { createEventDispatcher } from 'svelte'
import { Ref, Space } from '@anticrm/core'
import { Label, ActionIcon, IconClose, Button, EditBox } from '@anticrm/ui'
import { ActionIcon, Button, IconClose, Label } from '@anticrm/ui'
import TextArea from '@anticrm/ui/src/components/TextArea.svelte'
import { createEventDispatcher } from 'svelte'
import board from '../../plugin'
import CardsArchive from '../CardArchive.svelte'
import ListArchive from '../ListArchive.svelte'
import TextArea from '@anticrm/ui/src/components/TextArea.svelte'
export let space: Ref<Space>
const dispatch = createEventDispatcher()

View File

@ -234,6 +234,7 @@
window.removeEventListener('click', listener)
})
</script>
<div
bind:this={div}
class="{displayItems.length === 0 ? 'clear-mins' : 'buttons-group'} {kind === 'no-border' ? 'xsmall-gap' : 'xxsmall-gap'}"

View File

@ -105,6 +105,21 @@
}
Promise.all(promises)
}
function click (ev: any) {
if (ev.detail.presenter !== undefined && Array.isArray(channels)) {
const channel = channels[0]
if (channel !== undefined) {
showPanel(
view.component.EditDoc,
channel.attachedTo,
channel.attachedToClass,
'content',
ev.detail.presenter
)
}
}
}
</script>
<ChannelsDropdown
@ -118,4 +133,5 @@
on:change={(e) => {
if (editable) save(e.detail)
}}
on:click={click}
/>

View File

@ -36,7 +36,7 @@
view.component.EditDoc,
channel.attachedTo,
channel.attachedToClass,
'full',
'content',
ev.detail.presenter
)
}

View File

@ -15,13 +15,13 @@
-->
<script lang="ts">
import attachment from '@anticrm/attachment'
import { combineName,getFirstName,getLastName,Person } from '@anticrm/contact'
import { getCurrentAccount,Ref,Space } from '@anticrm/core'
import { combineName, getFirstName, getLastName, Person } from '@anticrm/contact'
import { getCurrentAccount, Ref, Space } from '@anticrm/core'
import { getResource } from '@anticrm/platform'
import { AttributeEditor,Avatar,createQuery,EditableAvatar,getClient } from '@anticrm/presentation'
import setting,{ IntegrationType } from '@anticrm/setting'
import { CircleButton,EditBox,IconActivity,Label } from '@anticrm/ui'
import { afterUpdate,createEventDispatcher,onMount } from 'svelte'
import { AttributeEditor, Avatar, createQuery, EditableAvatar, getClient } from '@anticrm/presentation'
import setting, { IntegrationType } from '@anticrm/setting'
import { CircleButton, EditBox, IconActivity, Label } from '@anticrm/ui'
import { afterUpdate, createEventDispatcher, onMount } from 'svelte'
import contact from '../plugin'
import ChannelsEditor from './ChannelsEditor.svelte'

View File

@ -102,7 +102,7 @@
}}>
{#if search !== ''}<div class="icon"><Icon icon={IconClose} size={'inline'} /></div>{/if}
</div>
<Button kind={'transparent'} size={'small'} icon={show ? IconView : IconViewHide} on:click={() => show = !show} />
<Button kind={'transparent'} size={'small'} icon={show ? IconView : IconViewHide} on:click={() => { show = !show }} />
{#if !hideAdd}<Button kind={'transparent'} size={'small'} icon={IconAdd} on:click={createTagElement} />{/if}
</div>
</div>

View File

@ -22,7 +22,7 @@
import { createQuery, getClient } from '@anticrm/presentation'
import setting, { Integration } from '@anticrm/setting'
import type { NewTelegramMessage, SharedTelegramMessage, TelegramMessage } from '@anticrm/telegram'
import { ActionIcon, Button, eventToHTMLElement, IconShare, ScrollBox, showPopup } from '@anticrm/ui'
import { Button, eventToHTMLElement, IconShare, Tooltip, Scroller, showPopup } from '@anticrm/ui'
import telegram from '../plugin'
import Connect from './Connect.svelte'
import TelegramIcon from './icons/Telegram.svelte'
@ -171,7 +171,7 @@
}
</script>
<div class="ac-header short mirror-tool divide">
<div class="telegram-header">
<div class="ac-header__wrap-title">
<div class="flex-center icon"><TelegramIcon size={'small'} /></div>
<div class="ac-header__wrap-description">
@ -179,22 +179,23 @@
<span class="ac-header__description">You and {formatName(object.name)}</span>
</div>
</div>
<ActionIcon
icon={IconShare}
size={'medium'}
label={telegram.string.Share}
direction={'bottom'}
action={async () => {
selectable = !selectable
}}
/>
<Tooltip label={telegram.string.Share}>
<Button
icon={IconShare}
kind={'transparent'}
size={'medium'}
on:click={async () => {
selectable = !selectable
}}
/>
</Tooltip>
</div>
<div class="h-full right-content">
<ScrollBox vertical stretch autoscrollable>
<div class="telegram-content" class:selectable>
<Scroller bottomStart autoscroll>
{#if messages && accounts}
<Messages messages={convertMessages(messages, accounts)} {selectable} bind:selected />
{/if}
</ScrollBox>
</Scroller>
</div>
<div class="ref-input" class:selectable>
@ -203,12 +204,12 @@
<span>{selected.size} messages selected</span>
<div class="flex">
<div>
<Button label={telegram.string.Cancel} size={'small'} on:click={clear} />
<Button label={telegram.string.Cancel} size={'medium'} on:click={clear} />
</div>
<div class="ml-3">
<Button
label={telegram.string.PublishSelected}
size={'small'}
size={'medium'}
kind={'primary'}
disabled={!selected.size}
on:click={share}
@ -247,12 +248,23 @@
</div>
<style lang="scss">
.telegram-header {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: nowrap;
margin: 0 2.5rem;
padding: 0;
height: 4rem;
min-height: 4rem;
border-bottom: 1px solid var(--divider-color);
}
.icon {
margin-right: 1rem;
width: 2.25rem;
height: 2.25rem;
color: var(--primary-button-color);
background-color: var(--primary-button-enabled);
color: var(--white-color);
background-color: var(--primary-bg-color);
border-radius: 50%;
}
@ -260,14 +272,18 @@
padding: 0 2.5rem 1.5rem;
&.selectable {
padding: 0.75rem 1.25rem 0.75rem 2.5rem;
padding: 1rem 2.5rem;
color: var(--theme-caption-color);
background-color: var(--accent-bg-color);
border-top: 1px solid var(--theme-card-divider);
}
}
.right-content {
flex-grow: 1;
padding: 1.5rem 1rem;
.telegram-content {
padding-bottom: 1.5rem;
min-height: 0;
height: 100%;
&.selectable { padding-bottom: 0; }
}
</style>

View File

@ -38,11 +38,12 @@
<style lang="scss">
.datetime-container {
justify-self: center;
margin: 0.3rem 0;
margin: 0.3rem auto;
padding: 0.25rem 0.75rem;
width: fit-content;
color: var(--theme-content-accent-color);
background-color: var(--theme-menu-divider);
border-radius: 1.25rem;
user-select: text;
}
</style>

View File

@ -33,13 +33,17 @@
</script>
<div
class="flex-between"
class="message-row"
class:selectable
class:selected-row={selected}
on:click={() => {
dispatch('select', message)
}}
>
<div class="flex-grow ml-6 flex" class:mr-6={!selectable} class:justify-end={!message.incoming}>
<div class="check-box">
{#if selectable}<CheckBox circle primary bind:checked={selected} />{/if}
</div>
<div class="message-container" class:out={!message.incoming}>
<div class="message" class:outcoming={!message.incoming} class:selected>
{#if showName}
<div class="name" style="color: {getPlatformColorForText(message.sender)}">{formatName(message.sender)}</div>
@ -55,22 +59,61 @@
</div>
</div>
</div>
{#if selectable}
<div class="ml-4 mr-1"><CheckBox circle primary bind:checked={selected} /></div>
{/if}
</div>
<style lang="scss">
.message-row {
display: flex;
justify-content: stretch;
align-items: center;
&.selectable {
cursor: pointer;
&:hover { background-color: var(--highlight-hover); }
&.selected-row {
background-color: var(--highlight-select);
&:hover { background-color: var(--highlight-hover); }
}
.message { cursor: pointer; }
.selected {
background-color: var(--primary-bg-color);
&:hover { background-color: var(--primary-bg-hover); }
}
}
}
.check-box {
display: flex;
justify-content: center;
width: 2.5rem;
min-width: 2.5rem;
pointer-events: none;
}
.message-container {
display: flex;
justify-content: stretch;
align-items: center;
flex-grow: 1;
margin-right: 2.5rem;
padding: .25rem 0;
&.out { justify-content: flex-end; }
}
.message {
padding: 0.5rem 0.75rem;
padding: .5rem .75rem;
max-width: 66%;
width: fit-content;
background-color: var(--theme-incoming-msg);
border-radius: 0.75rem;
border-radius: .75rem .75rem .75rem .25rem;
overflow-wrap: anywhere;
user-select: text;
cursor: default;
&.outcoming {
background-color: var(--theme-outcoming-msg);
border-radius: .75rem .75rem .25rem .75rem;
}
.time {
align-self: flex-end;
@ -81,12 +124,4 @@
white-space: nowrap;
}
}
.selectable {
margin: 0 0.25rem 0 0;
cursor: pointer;
.selected {
background-color: var(--primary-button-enabled);
}
}
</style>

View File

@ -15,7 +15,6 @@
-->
<script lang="ts">
import type { SharedTelegramMessage } from '@anticrm/telegram'
import { Grid } from '@anticrm/ui'
import Message from './Message.svelte'
import { Ref } from '@anticrm/core'
import DateView from './Date.svelte'
@ -49,21 +48,19 @@
}
</script>
<Grid column={1} rowGap={0.3}>
{#if messages}
{#each messages as message, i (message._id)}
{#if isNewDate(messages, i)}
<DateView {message} />
{/if}
<Message
{message}
{selectable}
selected={selected.has(message._id)}
showName={needName(messages, i)}
on:select={() => {
select(message._id)
}}
/>
{/each}
{/if}
</Grid>
{#if messages}
{#each messages as message, i (message._id)}
{#if isNewDate(messages, i)}
<DateView {message} />
{/if}
<Message
{message}
{selectable}
selected={selected.has(message._id)}
showName={needName(messages, i)}
on:select={() => {
select(message._id)
}}
/>
{/each}
{/if}

View File

@ -19,7 +19,7 @@
import CreateIssue from './CreateIssue.svelte'
export let currentSpace: Ref<Space>
async function newIssue (target: EventTarget | null): Promise<void> {
async function newIssue (): Promise<void> {
showPopup(CreateIssue, { space: currentSpace }, 'top')
}
</script>
@ -31,7 +31,7 @@
label={tracker.string.NewIssue}
justify={'left'}
width={'100%'}
on:click={() => newIssue(null)}
on:click={() => newIssue()}
/>
</div>
<Button icon={tracker.icon.Magnifier} on:click={async () => {}} />

View File

@ -25,9 +25,9 @@
import { onMount } from 'svelte'
import tracker from '../../plugin'
import CreateIssue from '../CreateIssue.svelte'
import AssigneePresenter from './AssigneePresenter.svelte'
import AssigneePresenter from './AssigneePresenter.svelte'
import IssuePresenter from './IssuePresenter.svelte'
import PriorityPresenter from './PriorityPresenter.svelte'
import PriorityPresenter from './PriorityPresenter.svelte'
export let currentSpace: Ref<Team>
export let baseMenuClass: Ref<Class<Doc>> | undefined = undefined

View File

@ -15,27 +15,22 @@
<script lang="ts">
import contact from '@anticrm/contact'
import { Class, Ref, SortingOrder, WithLookup } from '@anticrm/core'
// import Card from '../Card.svelte'
import { Panel } from '@anticrm/panel'
import { createQuery, getClient, UserBox } from '@anticrm/presentation'
import { StyledTextBox } from '@anticrm/text-editor'
import type { Issue, IssueStatus, Team } from '@anticrm/tracker'
import {
AnyComponent,
Button,
EditBox,
IconDownOutline,
IconUpOutline,
Label,
Scroller,
IconMoreH,
IconEdit
IconDownOutline, IconEdit, IconMoreH, IconUpOutline,
Label
} from '@anticrm/ui'
import { createEventDispatcher, onMount } from 'svelte'
import tracker from '../../plugin'
// import Card from '../Card.svelte'
import { Panel } from '@anticrm/panel'
import IssuePresenter from './IssuePresenter.svelte'
import StatusPresenter from './StatusPresenter.svelte'
import PriorityPresenter from './PriorityPresenter.svelte'
import StatusPresenter from './StatusPresenter.svelte'
export let _id: Ref<Issue>
export let _class: Ref<Class<Issue>>
@ -48,7 +43,6 @@
let issue: Issue | undefined
let currentTeam: Team | undefined
let issueStatuses: WithLookup<IssueStatus>[] | undefined
const fullSize: boolean = false
let innerWidth: number
$: _id &&
@ -96,10 +90,8 @@
{#if issue !== undefined}
<Panel
object={issue}
{fullSize}
showHeader={false}
isSubtitle={true}
position={'content'}
bind:innerWidth
on:close={() => {
dispatch('close')
@ -267,14 +259,5 @@
border-bottom: 1px solid var(--divider-color);
margin: 0.75rem 1.5rem 1.25rem 0;
}
&::before {
content: '';
position: absolute;
border-left: 1px solid var(--divider-color);
top: 1.125rem;
bottom: 1.125rem;
width: 0px;
}
}
</style>

View File

@ -13,27 +13,20 @@
// limitations under the License.
-->
<script lang="ts">
import { Class, Doc, FindOptions, Ref, getObjectValue, WithLookup } from '@anticrm/core'
import contact, { Employee } from '@anticrm/contact'
import { Class, Doc, FindOptions, getObjectValue, Ref, WithLookup } from '@anticrm/core'
import { getClient } from '@anticrm/presentation'
import { Issue, IssueStatus, Team } from '@anticrm/tracker'
import {
CheckBox,
showPopup,
Spinner,
IconMoreV,
Tooltip,
Component,
Button,
IconAdd,
eventToHTMLElement
Button, CheckBox, Component, eventToHTMLElement, IconAdd, IconMoreV, showPopup,
Spinner, Tooltip
} from '@anticrm/ui'
import { BuildModelKey } from '@anticrm/view'
import { buildModel, LoadingProps, Menu, SelectDirection } from '@anticrm/view-resources'
import { buildModel, LoadingProps, Menu } from '@anticrm/view-resources'
import { createEventDispatcher } from 'svelte'
import CreateIssue from '../CreateIssue.svelte'
import tracker from '../../plugin'
import { IssuesGroupByKeys, issuesGroupPresenterMap, IssuesOrderByKeys, issuesSortOrderMap } from '../../utils'
import CreateIssue from '../CreateIssue.svelte'
export let _class: Ref<Class<Doc>>
export let currentSpace: Ref<Team> | undefined = undefined
@ -97,7 +90,7 @@
dispatch('row-focus', object)
}
export const onElementSelected = (offset: 1 | -1 | 0, docObject?: Doc, dir?: SelectDirection) => {
export const onElementSelected = (offset: 1 | -1 | 0, docObject?: Doc) => {
let position =
(docObject !== undefined ? combinedGroupedIssues.findIndex((x) => x._id === docObject?._id) : selectedRowIndex) ??
-1

View File

@ -43,7 +43,7 @@
const listProvider = new ListSelectionProvider((offset: 1 | -1 | 0, of?: Doc, dir?: SelectDirection) => {
if (dir === 'vertical') {
issuesList.onElementSelected(offset, of, dir)
issuesList.onElementSelected(offset, of)
}
})

View File

@ -29,11 +29,11 @@
startDate: SortingOrder.Ascending
},
lookup: {
lead: contact.class.Employee,
lead: contact.class.Employee
}
}
async function showCreateDialog (ev: Event) {
async function showCreateDialog () {
showPopup(NewProject, { space, targetElement: null }, null)
}
</script>

View File

@ -39,6 +39,7 @@
"@anticrm/ui": "~0.6.0",
"@anticrm/task": "~0.6.0",
"@anticrm/notification": "~0.6.0",
"@anticrm/presentation": "~0.6.2"
"@anticrm/presentation": "~0.6.2",
"@anticrm/setting": "~0.6.1"
}
}

View File

@ -28,7 +28,7 @@
}
})
let lastKey: KeyboardEvent | undefined
// let lastKey: KeyboardEvent | undefined
async function updateActions (
context: ViewContext,
@ -68,7 +68,7 @@
console.log('no keyboard because', targetTagName, evt.target)
return
}
lastKey = evt
// lastKey = evt
for (const a of actions) {
// TODO: Handle multiple keys here
if (a.keyBinding?.find((it) => matchKey(evt, it)) !== undefined) {

View File

@ -14,11 +14,11 @@
// limitations under the License.
-->
<script lang="ts">
import contact, { formatName } from '@anticrm/contact'
import core, { Class, ClassifierKind, Doc, Hierarchy, Mixin, Obj, Ref } from '@anticrm/core'
import contact, { ChannelProvider, formatName } from '@anticrm/contact'
import core, { Class, ClassifierKind, Doc, getCurrentAccount, Hierarchy, Mixin, Obj, Ref, Space } from '@anticrm/core'
import notification from '@anticrm/notification'
import { Panel } from '@anticrm/panel'
import { Asset, getResource, translate } from '@anticrm/platform'
import { Asset, getResource, IntlString, translate } from '@anticrm/platform'
import {
AttributesBar,
createQuery,
@ -26,24 +26,25 @@
getClient,
KeyedAttribute
} from '@anticrm/presentation'
import { AnyComponent, Component, Label, PopupAlignment } from '@anticrm/ui'
import setting, { IntegrationType } from '@anticrm/setting'
import { AnyComponent, Button, Component, IconActivity } from '@anticrm/ui'
import Tooltip from '@anticrm/ui/src/components/Tooltip.svelte'
import view from '@anticrm/view'
import { createEventDispatcher, onDestroy } from 'svelte'
import { getCollectionCounter, getMixinStyle } from '../utils'
import { getCollectionCounter } from '../utils'
import ActionContext from './ActionContext.svelte'
import UpDownNavigator from './UpDownNavigator.svelte'
export let _id: Ref<Doc>
export let _class: Ref<Class<Doc>>
export let rightSection: AnyComponent | undefined = undefined
export let position: PopupAlignment | undefined = undefined
// export let position: PopupAlignment | undefined = undefined
let lastId: Ref<Doc> = _id
let lastClass: Ref<Class<Doc>> = _class
let object: Doc
let objectClass: Class<Doc>
let parentClass: Ref<Class<Doc>>
let fullSize: boolean = true
const client = getClient()
const hierarchy = client.getHierarchy()
@ -79,7 +80,7 @@
let prevSelected = selectedClass
let keys: KeyedAttribute[] = []
let collectionEditors: {key: KeyedAttribute, editor: AnyComponent} [] = []
let collectionEditors: { key: KeyedAttribute; editor: AnyComponent }[] = []
let mixins: Mixin<Doc>[] = []
@ -118,15 +119,11 @@
let ignoreMixins: Set<Ref<Mixin<Doc>>> = new Set<Ref<Mixin<Doc>>>()
async function updateKeys (): Promise<void> {
const filtredKeys = getFiltredKeys(
selectedClass ?? object._class,
ignoreKeys,
selectedClass !== objectClass._id ? objectClass._id : undefined
)
const filtredKeys = getFiltredKeys(selectedClass ?? object._class, ignoreKeys)
keys = collectionsFilter(filtredKeys, false)
const collectionKeys = collectionsFilter(filtredKeys, true)
const editors: {key: KeyedAttribute, editor: AnyComponent}[] = []
const editors: { key: KeyedAttribute; editor: AnyComponent }[] = []
for (const k of collectionKeys) {
const editor = await getCollectionEditor(k)
editors.push({ key: k, editor })
@ -245,20 +242,64 @@
}
let panelWidth: number = 0
let innerWidth: number = 0
const accountId = getCurrentAccount()._id
let channelProviders: ChannelProvider[] | undefined
let currentProviders: ChannelProvider[] | undefined
let integrations: Set<Ref<IntegrationType>> = new Set<Ref<IntegrationType>>()
let displayedIntegrations:
| {
icon: Asset | undefined
label: IntlString
presenter: AnyComponent | undefined
value: string
}[]
| undefined = []
client.findAll(contact.class.ChannelProvider, {}).then((res) => {
channelProviders = res
})
const settingsQuery = createQuery()
$: settingsQuery.query(
setting.class.Integration,
{ space: accountId as string as Ref<Space>, disabled: false },
(res) => {
integrations = new Set(res.map((p) => p.type))
}
)
const channelsQuery = createQuery()
$: _id &&
integrations &&
channelProviders &&
channelsQuery.query(contact.class.Channel, { attachedTo: _id }, (res) => {
const channels = res
currentProviders = channelProviders?.filter((provider) =>
provider.integrationType ? integrations.has(provider.integrationType as Ref<IntegrationType>) : false
)
displayedIntegrations = []
currentProviders?.forEach((provider) => {
displayedIntegrations?.push({
icon: provider.icon,
label: provider.label,
presenter: provider.presenter,
value: channels.filter((ch) => ch.provider === provider._id)[0].value
})
})
})
</script>
<ActionContext context={{
mode: 'editor'
}}/>
<ActionContext
context={{
mode: 'editor'
}}
/>
{#if object !== undefined && title !== undefined}
<Panel
{icon}
{title}
{rightSection}
{fullSize}
{object}
{position}
bind:panelWidth
bind:innerWidth
on:update={(ev) => _update(ev.detail)}
@ -267,7 +308,7 @@
}}
>
<svelte:fragment slot="navigate-actions">
<UpDownNavigator element={object}/>
<UpDownNavigator element={object} />
</svelte:fragment>
<svelte:fragment slot="subtitle">
{#if !headerLoading}
@ -289,6 +330,33 @@
</div>
{/if}
</svelte:fragment>
<svelte:fragment slot="actions">
{#if displayedIntegrations && displayedIntegrations.length > 0}
<div class="actions-divider" />
{#each displayedIntegrations as pr}
<Tooltip label={pr.label}>
<Button
icon={pr.icon}
size={'medium'}
kind={'transparent'}
highlight={rightSection === pr.presenter}
on:click={() => {
if (rightSection !== pr.presenter) rightSection = pr.presenter
}}
/>
</Tooltip>
{/each}
<Button
icon={IconActivity}
size={'medium'}
kind={'transparent'}
highlight={!rightSection}
on:click={() => {
if (rightSection) rightSection = undefined
}}
/>
{/if}
</svelte:fragment>
<div class="main-editor">
{#if mainEditor}
<Component
@ -301,36 +369,11 @@
getMixins()
}}
on:click={(ev) => {
fullSize = true
rightSection = ev.detail.presenter
}}
/>
{/if}
</div>
{#if mixins.length > 0}
<div class="mixin-container">
<div
class="mixin-selector"
style={getMixinStyle(objectClass._id, selectedClass === objectClass._id)}
on:click={() => {
selectedClass = objectClass._id
}}
>
<Label label={objectClass.label} />
</div>
{#each mixins as mixin}
<div
class="mixin-selector"
style={getMixinStyle(mixin._id, selectedClass === mixin._id)}
on:click={() => {
selectedClass = mixin._id
}}
>
<Label label={mixin.label} />
</div>
{/each}
</div>
{/if}
{#each collectionEditors as collection}
{#if collection.editor}
<div class="mt-14">
@ -345,7 +388,7 @@
[collection.key.key]: getCollectionCounter(hierarchy, object, collection.key)
}}
/>
</div>
</div>
{/if}
{/each}
</Panel>
@ -357,26 +400,12 @@
justify-content: center;
flex-direction: column;
}
.mixin-container {
margin-top: 2rem;
display: flex;
.mixin-selector {
margin-left: 0.5rem;
cursor: pointer;
height: 1.5rem;
min-width: 5.25rem;
border-radius: 0.5rem;
font-weight: 500;
font-size: 0.625rem;
text-transform: uppercase;
color: var(--theme-caption-color);
display: flex;
align-items: center;
justify-content: center;
}
.actions-divider {
margin: 0 0.25rem;
min-width: 1px;
width: 1px;
height: 1.5rem;
background-color: var(--divider-color);
}
</style>

View File

@ -38,7 +38,7 @@
actions = result.map(a => ({
label: a.label,
icon: a.icon as Asset,
action: async (props:any, evt: Event) => { invokeAction(evt, a.action) }
action: async (_:any, evt: Event) => { invokeAction(evt, a.action) }
}))
loaded = 1
})

View File

@ -21,7 +21,6 @@
import { CheckBox, Component, IconDown, IconUp, Label, Loading, showPopup, Spinner } from '@anticrm/ui'
import { BuildModelKey } from '@anticrm/view'
import { createEventDispatcher } from 'svelte'
import { SelectDirection } from '../selection'
import { buildModel, LoadingProps } from '../utils'
import Menu from './Menu.svelte'
@ -128,7 +127,7 @@
dispatch('row-focus', object)
}
export function select (offset: 1 | -1 | 0, of?: Doc, dir?: SelectDirection): void {
export function select (offset: 1 | -1 | 0, of?: Doc): void {
let pos = (((of !== undefined) ? objects.findIndex(it => it._id === of._id) : selection) ?? -1)
pos += offset
if (pos < 0) {

View File

@ -36,7 +36,7 @@
(offset: 1 | -1 | 0, of?: Doc, dir?: SelectDirection) => {
if (dir === 'vertical') {
// Select next
table.select(offset, of, dir)
table.select(offset, of)
}
}
)

View File

@ -303,7 +303,10 @@
if (window.innerWidth < 1100 && !navFloat) {
visibileNav = false
navFloat = true
} else if (window.innerWidth >= 1100 && navFloat) navFloat = false
} else if (window.innerWidth >= 1100 && navFloat) {
navFloat = false
visibileNav = true
}
}
const checkOnHide = (): void => {
if (visibileNav && navFloat) visibileNav = false

View File

@ -53,7 +53,7 @@ test.describe('recruit tests', () => {
await page.click('text=Candidates')
await page.click('text=Andrey P.')
await page.locator('.mixin-selector').locator('text="Candidate"').click()
// await page.locator('.mixin-selector').locator('text="Candidate"').click()
// Click on Add button
await page.click('.applications-container .flex-row-center .flex-center')