mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-16 13:21:57 +00:00
Signed-off-by: budaeva <irina.budaeva@xored.com>
This commit is contained in:
parent
eb9526f015
commit
21f0928e71
@ -16,13 +16,17 @@
|
|||||||
import contact, { Employee, EmployeeAccount } from '@anticrm/contact'
|
import contact, { Employee, EmployeeAccount } from '@anticrm/contact'
|
||||||
import { Account, DocumentQuery, Ref, SortingOrder, Space } from '@anticrm/core'
|
import { Account, DocumentQuery, Ref, SortingOrder, Space } from '@anticrm/core'
|
||||||
import { translate } from '@anticrm/platform'
|
import { translate } from '@anticrm/platform'
|
||||||
import { Label, Scroller, SearchEdit } from '@anticrm/ui'
|
import { IconAdd, Label, Scroller, SearchEdit } from '@anticrm/ui'
|
||||||
|
import { createEventDispatcher } from 'svelte'
|
||||||
import presentation from '../plugin'
|
import presentation from '../plugin'
|
||||||
import { getClient } from '../utils'
|
import { getClient } from '../utils'
|
||||||
import UserInfo from './UserInfo.svelte'
|
import UserInfo from './UserInfo.svelte'
|
||||||
|
|
||||||
export let space: Space
|
export let space: Space
|
||||||
|
export let withAddButton: boolean = false
|
||||||
|
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
const hierarchy = client.getHierarchy()
|
const hierarchy = client.getHierarchy()
|
||||||
$: label = hierarchy.getClass(space._class).label
|
$: label = hierarchy.getClass(space._class).label
|
||||||
let spaceClass = ''
|
let spaceClass = ''
|
||||||
@ -77,6 +81,16 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
{#if !isSearch && withAddButton}
|
||||||
|
<div class="item fs-title">
|
||||||
|
<div class="flex-row-center" on:click={() => dispatch('addMembers')}>
|
||||||
|
<div class="flex-center ml-1 mr-1"><IconAdd size={'large'} /></div>
|
||||||
|
<div class="flex-col ml-2 min-w-0 content-accent-color">
|
||||||
|
<Label label={presentation.string.Add} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
{#each current as person}
|
{#each current as person}
|
||||||
<div class="item fs-title"><UserInfo size={'medium'} value={person} /></div>
|
<div class="item fs-title"><UserInfo size={'medium'} value={person} /></div>
|
||||||
{/each}
|
{/each}
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
export let placeholder: IntlString = presentation.string.Search
|
export let placeholder: IntlString = presentation.string.Search
|
||||||
export let selectedUsers: Ref<Person>[] = []
|
export let selectedUsers: Ref<Person>[] = []
|
||||||
export let ignoreUsers: Ref<Person>[] = []
|
export let ignoreUsers: Ref<Person>[] = []
|
||||||
|
export let shadows: boolean = true
|
||||||
|
|
||||||
let search: string = ''
|
let search: string = ''
|
||||||
let objects: Person[] = []
|
let objects: Person[] = []
|
||||||
@ -72,7 +73,7 @@
|
|||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="selectPopup">
|
<div class="selectPopup" class:plainContainer={!shadows}>
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<input bind:this={input} type="text" bind:value={search} placeholder={phTraslate} on:change />
|
<input bind:this={input} type="text" bind:value={search} placeholder={phTraslate} on:change />
|
||||||
</div>
|
</div>
|
||||||
@ -110,3 +111,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.plainContainer {
|
||||||
|
color: var(--caption-color);
|
||||||
|
background-color: var(--body-color);
|
||||||
|
border: 1px solid var(--button-border-color);
|
||||||
|
border-radius: .25rem;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -57,6 +57,7 @@
|
|||||||
"SharedBy": "Shared by {name} {time}",
|
"SharedBy": "Shared by {name} {time}",
|
||||||
"LeaveChannel": "Leave channel",
|
"LeaveChannel": "Leave channel",
|
||||||
"ChannelBrowser": "Channel browser",
|
"ChannelBrowser": "Channel browser",
|
||||||
"SavedItems": "Saved items"
|
"SavedItems": "Saved items",
|
||||||
|
"AddMembersHeader": "Add members to {channel}:"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -56,6 +56,7 @@
|
|||||||
"SharedBy": "Доступ открыт {name} {time}",
|
"SharedBy": "Доступ открыт {name} {time}",
|
||||||
"LeaveChannel": "Покинуть канал",
|
"LeaveChannel": "Покинуть канал",
|
||||||
"ChannelBrowser": "Браузер каналов",
|
"ChannelBrowser": "Браузер каналов",
|
||||||
"SavedItems": "Сохраненные объекты"
|
"SavedItems": "Сохраненные объекты",
|
||||||
|
"AddMembersHeader": "Добавить пользователей в {channel}:"
|
||||||
}
|
}
|
||||||
}
|
}
|
107
plugins/chunter-resources/src/components/AddMembersPopup.svelte
Normal file
107
plugins/chunter-resources/src/components/AddMembersPopup.svelte
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Channel } from '@anticrm/chunter'
|
||||||
|
import contact, { Employee, EmployeeAccount, formatName } from '@anticrm/contact'
|
||||||
|
import core, { Ref } from '@anticrm/core'
|
||||||
|
import presentation, { getClient, UsersPopup } from '@anticrm/presentation'
|
||||||
|
import { Label, Button, ActionIcon, IconClose } from '@anticrm/ui'
|
||||||
|
import { createEventDispatcher } from 'svelte'
|
||||||
|
import chunter from '../plugin'
|
||||||
|
|
||||||
|
export let channel: Channel
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
const client = getClient()
|
||||||
|
|
||||||
|
let membersToAdd: EmployeeAccount[] = []
|
||||||
|
let channelMembers: Ref<Employee>[] = []
|
||||||
|
client.findAll(core.class.Account, { _id: { $in: channel.members } }).then((res) => {
|
||||||
|
channelMembers = res
|
||||||
|
.filter((e) => e._class === contact.class.EmployeeAccount)
|
||||||
|
.map((e) => (e as EmployeeAccount).employee)
|
||||||
|
})
|
||||||
|
|
||||||
|
async function changeMembersToAdd (employees: Ref<Employee>[]) {
|
||||||
|
if (employees) {
|
||||||
|
await client.findAll(contact.class.EmployeeAccount, { employee: { $in: employees } }).then((res) => {
|
||||||
|
if (res) {
|
||||||
|
membersToAdd = res
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$: selectedEmployees = membersToAdd.map((e) => e.employee)
|
||||||
|
|
||||||
|
function removeMember (_id: Ref<EmployeeAccount>) {
|
||||||
|
membersToAdd = membersToAdd.filter((m) => m._id !== _id)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="antiPopup antiPopup-withHeader">
|
||||||
|
<div class="ap-header flex-between header">
|
||||||
|
<div class="ap-caption">
|
||||||
|
<Label label={chunter.string.AddMembersHeader} params={{ channel: channel.name }} />
|
||||||
|
</div>
|
||||||
|
<div class="tool">
|
||||||
|
<ActionIcon
|
||||||
|
icon={IconClose}
|
||||||
|
size={'small'}
|
||||||
|
action={() => {
|
||||||
|
dispatch('close')
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{#if membersToAdd.length}
|
||||||
|
<div class="flex-row-top flex-wrap ml-6 mr-6 mt-4">
|
||||||
|
{#each membersToAdd as m}
|
||||||
|
<div class=" mr-2 p-1 item">
|
||||||
|
{formatName(m.name)}
|
||||||
|
<div class="tool">
|
||||||
|
<ActionIcon
|
||||||
|
icon={IconClose}
|
||||||
|
size={'small'}
|
||||||
|
action={() => {
|
||||||
|
removeMember(m._id)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
<div class="ml-8 mr-8 mb-6 mt-4">
|
||||||
|
<UsersPopup
|
||||||
|
selected={undefined}
|
||||||
|
_class={contact.class.Employee}
|
||||||
|
multiSelect={true}
|
||||||
|
allowDeselect={true}
|
||||||
|
selectedUsers={selectedEmployees}
|
||||||
|
ignoreUsers={channelMembers}
|
||||||
|
shadows={false}
|
||||||
|
on:update={(ev) => changeMembersToAdd(ev.detail)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
on:click={() => {
|
||||||
|
dispatch(
|
||||||
|
'update',
|
||||||
|
membersToAdd.map((m) => m._id)
|
||||||
|
)
|
||||||
|
dispatch('close')
|
||||||
|
}}
|
||||||
|
label={presentation.string.Add}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.header {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
width: fit-content;
|
||||||
|
background-color: var(--popup-bg-hover);
|
||||||
|
}
|
||||||
|
</style>
|
@ -20,6 +20,7 @@
|
|||||||
import chunter from '../plugin'
|
import chunter from '../plugin'
|
||||||
import { classIcon } from '../utils'
|
import { classIcon } from '../utils'
|
||||||
import Header from './Header.svelte'
|
import Header from './Header.svelte'
|
||||||
|
import Lock from './icons/Lock.svelte'
|
||||||
|
|
||||||
export let spaceId: Ref<Channel> | undefined
|
export let spaceId: Ref<Channel> | undefined
|
||||||
|
|
||||||
@ -40,7 +41,7 @@
|
|||||||
<div class="ac-header divide full">
|
<div class="ac-header divide full">
|
||||||
{#if channel}
|
{#if channel}
|
||||||
<Header
|
<Header
|
||||||
icon={classIcon(client, channel._class)}
|
icon={channel.private ? Lock : classIcon(client, channel._class)}
|
||||||
label={channel.name}
|
label={channel.name}
|
||||||
description={channel.topic}
|
description={channel.topic}
|
||||||
on:click={onSpaceEdit}
|
on:click={onSpaceEdit}
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
|
let isPrivate: boolean = false
|
||||||
let name: string = ''
|
let name: string = ''
|
||||||
export function canClose (): boolean {
|
export function canClose (): boolean {
|
||||||
return name === ''
|
return name === ''
|
||||||
@ -33,7 +34,7 @@
|
|||||||
client.createDoc(chunter.class.Channel, core.space.Space, {
|
client.createDoc(chunter.class.Channel, core.space.Space, {
|
||||||
name,
|
name,
|
||||||
description: '',
|
description: '',
|
||||||
private: false,
|
private: isPrivate,
|
||||||
archived: false,
|
archived: false,
|
||||||
members: [getCurrentAccount()._id]
|
members: [getCurrentAccount()._id]
|
||||||
})
|
})
|
||||||
@ -57,6 +58,10 @@
|
|||||||
maxWidth={'16rem'}
|
maxWidth={'16rem'}
|
||||||
focus
|
focus
|
||||||
/>
|
/>
|
||||||
<ToggleWithLabel label={chunter.string.MakePrivate} description={chunter.string.MakePrivateDescription} />
|
<ToggleWithLabel
|
||||||
|
label={chunter.string.MakePrivate}
|
||||||
|
description={chunter.string.MakePrivateDescription}
|
||||||
|
bind:on={isPrivate}
|
||||||
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</SpaceCreateCard>
|
</SpaceCreateCard>
|
||||||
|
@ -15,15 +15,18 @@
|
|||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { ChunterSpace } from '@anticrm/chunter'
|
import { ChunterSpace } from '@anticrm/chunter'
|
||||||
|
import { EmployeeAccount } from '@anticrm/contact'
|
||||||
import type { Class, Ref } from '@anticrm/core'
|
import type { Class, Ref } from '@anticrm/core'
|
||||||
import type { IntlString } from '@anticrm/platform'
|
import type { IntlString } from '@anticrm/platform'
|
||||||
import { createQuery, getClient, Members } from '@anticrm/presentation'
|
import { createQuery, getClient, Members } from '@anticrm/presentation'
|
||||||
import { Icon, IconClose, Label, ActionIcon, Scroller } from '@anticrm/ui'
|
import { ActionIcon, Icon, IconClose, Label, Scroller, showPopup } from '@anticrm/ui'
|
||||||
import { createEventDispatcher } from 'svelte'
|
import { createEventDispatcher } from 'svelte'
|
||||||
|
|
||||||
import chunter from '../plugin'
|
import chunter from '../plugin'
|
||||||
|
import AddMembersPopup from './AddMembersPopup.svelte'
|
||||||
import EditChannelDescriptionTab from './EditChannelDescriptionTab.svelte'
|
import EditChannelDescriptionTab from './EditChannelDescriptionTab.svelte'
|
||||||
import EditChannelSettingsTab from './EditChannelSettingsTab.svelte'
|
import EditChannelSettingsTab from './EditChannelSettingsTab.svelte'
|
||||||
|
import Lock from './icons/Lock.svelte'
|
||||||
|
|
||||||
export let _id: Ref<ChunterSpace>
|
export let _id: Ref<ChunterSpace>
|
||||||
export let _class: Ref<Class<ChunterSpace>>
|
export let _class: Ref<Class<ChunterSpace>>
|
||||||
@ -46,6 +49,24 @@
|
|||||||
...(_class === chunter.class.Channel ? [chunter.string.Settings] : [])
|
...(_class === chunter.class.Channel ? [chunter.string.Settings] : [])
|
||||||
]
|
]
|
||||||
let selectedTabIndex = 0
|
let selectedTabIndex = 0
|
||||||
|
|
||||||
|
function openAddMembersPopup () {
|
||||||
|
showPopup(
|
||||||
|
AddMembersPopup,
|
||||||
|
{ channel },
|
||||||
|
undefined,
|
||||||
|
() => {},
|
||||||
|
async (membersIds: Ref<EmployeeAccount>[]) => {
|
||||||
|
if (membersIds) {
|
||||||
|
membersIds
|
||||||
|
.filter((m: Ref<EmployeeAccount>) => !channel.members.includes(m))
|
||||||
|
.forEach(async (m) => {
|
||||||
|
await client.update(channel, { $push: { members: m } })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
@ -57,7 +78,11 @@
|
|||||||
<div class="ac-header short mirror divide">
|
<div class="ac-header short mirror divide">
|
||||||
<div class="ac-header__wrap-title">
|
<div class="ac-header__wrap-title">
|
||||||
<div class="ac-header__icon">
|
<div class="ac-header__icon">
|
||||||
{#if clazz.icon}<Icon icon={clazz.icon} size={'medium'} />{/if}
|
{#if channel}
|
||||||
|
{#if channel.private}
|
||||||
|
<Lock size={'medium'} />
|
||||||
|
{:else if clazz.icon}<Icon icon={clazz.icon} size={'medium'} />{/if}
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="ac-header__title"><Label label={clazz.label} /></div>
|
<div class="ac-header__title"><Label label={clazz.label} /></div>
|
||||||
</div>
|
</div>
|
||||||
@ -91,7 +116,7 @@
|
|||||||
<EditChannelDescriptionTab {channel} on:close />
|
<EditChannelDescriptionTab {channel} on:close />
|
||||||
</Scroller>
|
</Scroller>
|
||||||
{:else if selectedTabIndex === 1}
|
{:else if selectedTabIndex === 1}
|
||||||
<Members space={channel} />
|
<Members space={channel} withAddButton={true} on:addMembers={openAddMembersPopup} />
|
||||||
{:else if selectedTabIndex === 2}
|
{:else if selectedTabIndex === 2}
|
||||||
<EditChannelSettingsTab {channel} on:close />
|
<EditChannelSettingsTab {channel} on:close />
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -14,9 +14,9 @@
|
|||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Asset } from '@anticrm/platform'
|
import type { Asset } from '@anticrm/platform'
|
||||||
import { Icon } from '@anticrm/ui'
|
import { AnySvelteComponent, Icon } from '@anticrm/ui'
|
||||||
|
|
||||||
export let icon: Asset | undefined
|
export let icon: Asset | AnySvelteComponent | undefined
|
||||||
export let label: string
|
export let label: string
|
||||||
export let description: string | undefined
|
export let description: string | undefined
|
||||||
</script>
|
</script>
|
||||||
|
10
plugins/chunter-resources/src/components/icons/Lock.svelte
Normal file
10
plugins/chunter-resources/src/components/icons/Lock.svelte
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
export let size: 'small' | 'medium' | 'large'
|
||||||
|
const fill: string = 'currentColor'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svg class="svg-{size}" {fill} viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path
|
||||||
|
d="M13,6.9h-1.1V4.8c0-2.2-1.8-3.9-3.9-3.9c-2.2,0-3.9,1.8-3.9,3.9v2.1H3c-0.9,0-1.6,0.7-1.6,1.6v5.3 c0,0.9,0.7,1.6,1.6,1.6h10c0.9,0,1.6-0.7,1.6-1.6V8.5C14.6,7.6,13.9,6.9,13,6.9z M5.3,4.8c0-1.5,1.2-2.7,2.7-2.7s2.7,1.2,2.7,2.7 v2.1H5.3V4.8z M13.4,13.8c0,0.2-0.2,0.4-0.4,0.4H3c-0.2,0-0.4-0.2-0.4-0.4V8.5c0-0.2,0.2-0.4,0.4-0.4h10c0.2,0,0.4,0.2,0.4,0.4V13.8 z"
|
||||||
|
/>
|
||||||
|
</svg>
|
@ -80,6 +80,7 @@ export default mergeIds(chunterId, chunter, {
|
|||||||
SharedBy: '' as IntlString,
|
SharedBy: '' as IntlString,
|
||||||
LeaveChannel: '' as IntlString,
|
LeaveChannel: '' as IntlString,
|
||||||
ChannelBrowser: '' as IntlString,
|
ChannelBrowser: '' as IntlString,
|
||||||
SavedItems: '' as IntlString
|
SavedItems: '' as IntlString,
|
||||||
|
AddMembersHeader: '' as IntlString
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user