Allow attachments customizations. (#2414)

Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
Andrey Sobolev 2022-12-03 01:10:53 +07:00 committed by GitHub
parent 0ba152665c
commit 1bcc1dfc82
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 96 additions and 52 deletions

View File

@ -79,6 +79,8 @@
export let field: string | undefined = undefined
export let autoOverflow = false
const ydoc = (getContext(CollaborationIds.Doc) as Y.Doc | undefined) ?? new Y.Doc()
const contextProvider = getContext(CollaborationIds.Provider) as WebsocketProvider | undefined
const wsProvider =
@ -464,7 +466,7 @@
let showDiff = true
</script>
<div class="ref-container">
<div class="ref-container" class:autoOverflow>
<div class="flex">
{#if isFormatting && !readonly}
<div class="formatPanel buttons-group xsmall-gap mb-4">
@ -709,4 +711,7 @@
span.deletion {
text-decoration: line-through;
}
.autoOverflow {
overflow: auto;
}
</style>

View File

@ -13,11 +13,13 @@
// limitations under the License.
-->
<script lang="ts">
import { Class, Doc, Ref, Space } from '@hcengineering/core'
import { Attachment } from '@hcengineering/attachment'
import { Class, Data, Doc, Ref, Space } from '@hcengineering/core'
import { getClient } from '@hcengineering/presentation'
import { Button, IconAdd } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import { createAttachments } from '../utils'
import attachment from '../plugin'
export let loading: number = 0
export let inputFile: HTMLInputElement
@ -25,6 +27,8 @@
export let objectClass: Ref<Class<Doc>>
export let objectId: Ref<Doc>
export let space: Ref<Space>
export let attachmentClass: Ref<Class<Attachment>> = attachment.class.Attachment
export let attachmentClassOptions: Partial<Data<Attachment>> = {}
const client = getClient()
const dispatch = createEventDispatcher()
@ -35,7 +39,7 @@
loading++
try {
await createAttachments(client, list, { objectClass, objectId, space })
await createAttachments(client, list, { objectClass, objectId, space }, attachmentClass, attachmentClassOptions)
} finally {
loading--
}

View File

@ -14,9 +14,10 @@
// limitations under the License.
-->
<script lang="ts">
import { Class, Doc, DocumentQuery, Ref, Space } from '@hcengineering/core'
import { Icon, Label, Spinner, resizeObserver, Scroller } from '@hcengineering/ui'
import view from '@hcengineering/view'
import { Attachment } from '@hcengineering/attachment'
import { Class, Data, Doc, DocumentQuery, Ref, Space } from '@hcengineering/core'
import { Icon, Label, resizeObserver, Scroller, Spinner } from '@hcengineering/ui'
import view, { BuildModelKey } from '@hcengineering/view'
import { Table } from '@hcengineering/view-resources'
import attachment from '../plugin'
import AddAttachment from './AddAttachment.svelte'
@ -28,7 +29,11 @@
export let space: Ref<Space>
export let _class: Ref<Class<Doc>>
export let query: DocumentQuery<Doc> = {}
export let attachmentClass: Ref<Class<Attachment>> = attachment.class.Attachment
export let attachmentClassOptions: Partial<Data<Attachment>> = {}
export let extraConfig: (BuildModelKey | string)[] = []
export let readonly = false
export let showHeader = true
export let attachments: number | undefined = undefined
let inputFile: HTMLInputElement
@ -40,19 +45,33 @@
<div class="antiSection" use:resizeObserver={(element) => (wSection = element.clientWidth)}>
<div class="antiSection-header">
<div class="antiSection-header__icon">
<Icon icon={IconAttachment} size={'small'} />
{#if showHeader}
<Icon icon={IconAttachment} size={'small'} />
{/if}
</div>
<span class="antiSection-header__title"><Label label={attachment.string.Attachments} /></span>
<span class="antiSection-header__title">
{#if showHeader}
<Label label={attachment.string.Attachments} />
{/if}
</span>
<div class="buttons-group small-gap">
{#if loading}
<Spinner />
{:else}
<AddAttachment bind:loading bind:inputFile objectClass={_class} {objectId} {space} />
{:else if !readonly}
<AddAttachment
bind:loading
bind:inputFile
objectClass={_class}
{objectId}
{space}
{attachmentClass}
{attachmentClassOptions}
/>
{/if}
</div>
</div>
{#if !loading && (attachments === null || attachments === 0)}
{#if !loading && (attachments === null || attachments === 0) && !readonly}
<AttachmentDroppable bind:loading bind:dragover objectClass={_class} {objectId} {space}>
<div class="antiSection-empty attachments flex-col mt-3" class:solid={dragover}>
<div class="flex-center content-accent-color">
@ -74,7 +93,7 @@
{:else if wSection < 640}
<Scroller horizontal>
<Table
_class={attachment.class.Attachment}
_class={attachmentClass}
config={[
'',
'description',
@ -84,6 +103,7 @@
label: attachment.string.Pinned,
sortingKey: 'pinned'
},
...extraConfig,
'lastModified'
]}
options={{ sort: { pinned: -1 } }}
@ -92,11 +112,12 @@
on:content={(evt) => {
attachments = evt.detail.length
}}
{readonly}
/>
</Scroller>
{:else}
<Table
_class={attachment.class.Attachment}
_class={attachmentClass}
config={[
'',
'description',
@ -106,6 +127,7 @@
label: attachment.string.Pinned,
sortingKey: 'pinned'
},
...extraConfig,
'lastModified'
]}
options={{ sort: { pinned: -1 } }}
@ -114,6 +136,7 @@
on:content={(evt) => {
attachments = evt.detail.length
}}
{readonly}
/>
{/if}
</div>

View File

@ -14,7 +14,8 @@
// limitations under the License.
//
import type { Class, Doc, Ref, Space, TxOperations as Client } from '@hcengineering/core'
import { Attachment } from '@hcengineering/attachment'
import type { Class, Data, Doc, Ref, Space, TxOperations as Client } from '@hcengineering/core'
import login from '@hcengineering/login'
import { getMetadata, setPlatformStatus, unknownError } from '@hcengineering/platform'
@ -77,7 +78,9 @@ export async function deleteFile (id: string): Promise<void> {
export async function createAttachments (
client: Client,
list: FileList,
attachTo: { objectClass: Ref<Class<Doc>>, space: Ref<Space>, objectId: Ref<Doc> }
attachTo: { objectClass: Ref<Class<Doc>>, space: Ref<Space>, objectId: Ref<Doc> },
attachmentClass: Ref<Class<Attachment>> = attachment.class.Attachment,
extraData: Partial<Data<Attachment>> = {}
): Promise<void> {
const { objectClass, objectId, space } = attachTo
try {
@ -85,7 +88,8 @@ export async function createAttachments (
const file = list.item(index)
if (file !== null) {
const uuid = await uploadFile(file, { space, attachedTo: objectId })
await client.addCollection(attachment.class.Attachment, space, objectId, objectClass, 'attachments', {
await client.addCollection(attachmentClass, space, objectId, objectClass, 'attachments', {
...extraData,
name: file.name,
file: uuid,
type: file.type,

View File

@ -29,6 +29,7 @@
export let showLabel: IntlString | undefined = undefined
export let defaultCollapsed = false
export let draft = false
export let showHeader: boolean = true
const client = getClient()
const hierarchy = client.getHierarchy()
@ -47,42 +48,44 @@
</script>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
class="attrbar-header"
class:collapsed
on:click={() => {
collapsed = !collapsed
}}
>
<div class="flex-row-center">
<span class="overflow-label">
<Label {label} />
</span>
<div class="icon-arrow">
<svg fill="var(--dark-color)" viewBox="0 0 6 6" xmlns="http://www.w3.org/2000/svg">
<path d="M0,0L6,3L0,6Z" />
</svg>
{#if showHeader}
<div
class="attrbar-header"
class:collapsed
on:click={() => {
collapsed = !collapsed
}}
>
<div class="flex-row-center">
<span class="overflow-label">
<Label {label} />
</span>
<div class="icon-arrow">
<svg fill="var(--dark-color)" viewBox="0 0 6 6" xmlns="http://www.w3.org/2000/svg">
<path d="M0,0L6,3L0,6Z" />
</svg>
</div>
</div>
<div class="tool">
<Button
icon={setting.icon.Setting}
kind={'transparent'}
showTooltip={{ label: setting.string.ClassSetting }}
on:click={(ev) => {
ev.stopPropagation()
const loc = getCurrentLocation()
loc.path[2] = settingId
loc.path[3] = 'setting'
loc.path[4] = 'classes'
loc.path.length = 5
loc.query = { _class }
loc.fragment = undefined
navigate(loc)
}}
/>
</div>
</div>
<div class="tool">
<Button
icon={setting.icon.Setting}
kind={'transparent'}
showTooltip={{ label: setting.string.ClassSetting }}
on:click={(ev) => {
ev.stopPropagation()
const loc = getCurrentLocation()
loc.path[2] = settingId
loc.path[3] = 'setting'
loc.path[4] = 'classes'
loc.path.length = 5
loc.query = { _class }
loc.fragment = undefined
navigate(loc)
}}
/>
</div>
</div>
{/if}
{#if keys.length}
<div class="collapsed-container" class:collapsed>
<AttributesBar {_class} {object} keys={keys.map((p) => p.key)} {readonly} {draft} on:update />

View File

@ -44,6 +44,7 @@
export let baseMenuClass: Ref<Class<Doc>> | undefined = undefined
export let config: (BuildModelKey | string)[]
export let tableId: string | undefined = undefined
export let readonly = false
// If defined, will show a number of dummy items before real data will appear.
export let loadingProps: LoadingProps | undefined = undefined
@ -243,7 +244,11 @@
on:mouseover={() => onRow(object)}
on:focus={() => {}}
bind:this={refs[row]}
on:contextmenu|preventDefault={(ev) => showMenu(ev, object, row)}
on:contextmenu|preventDefault={(ev) => {
if (!readonly) {
showMenu(ev, object, row)
}
}}
>
{#each model as attribute, cell}
{#if !cell}