Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
Andrey Sobolev 2022-01-11 16:07:29 +07:00 committed by GitHub
parent aabef475a6
commit decf27ef0d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 95 additions and 53 deletions

View File

@ -21,6 +21,7 @@
import attachment from '@anticrm/attachment'
export let objectId: Ref<Doc>
export let attachments: number
</script>
@ -29,4 +30,5 @@
config={['', 'lastModified']}
options={ {} }
query={ { attachedTo: objectId } }
loadingProps={{ length: attachments }}
/>

View File

@ -14,26 +14,20 @@
// limitations under the License.
-->
<script lang="ts">
import attachment from '../plugin'
import type { Attachment } from '@anticrm/attachment'
import type { Class, Doc, Ref, Space } from '@anticrm/core'
import { Class, Doc, Ref, Space } from '@anticrm/core'
import { setPlatformStatus, unknownError } from '@anticrm/platform'
import { createQuery, getClient } from '@anticrm/presentation'
import { getClient } from '@anticrm/presentation'
import { CircleButton, IconAdd, Label, Spinner } from '@anticrm/ui'
import { Table } from '@anticrm/view-resources'
import attachment from '../plugin'
import { uploadFile } from '../utils'
import UploadDuo from './icons/UploadDuo.svelte'
export let objectId: Ref<Doc>
export let space: Ref<Space>
export let _class: Ref<Class<Doc>>
let attachments: Attachment[] = []
const query = createQuery()
$: query.query(attachment.class.Attachment, { attachedTo: objectId }, (result) => {
attachments = result
})
export let attachments: number
let inputFile: HTMLInputElement
let loading = 0
@ -108,7 +102,7 @@
/>
</div>
{#if attachments.length === 0 && !loading}
{#if (attachments === 0) && !loading}
<div
class="flex-col-center mt-5 zone-container"
class:solid={dragover}
@ -137,6 +131,7 @@
config={['', 'lastModified']}
options={{}}
query={{ attachedTo: objectId }}
loadingProps={ { length: attachments } }
/>
{/if}
</div>

View File

@ -24,7 +24,7 @@
</script>
{#if value && value.attachments && value.attachments > 0}
<Tooltip label={'Attachments (' + value.attachments + ')'} component={AttachmentPopup} props={{ objectId: value._id }}>
<Tooltip label={'Attachments (' + value.attachments + ')'} component={AttachmentPopup} props={{ objectId: value._id, attachments: value.attachments }}>
<div class="sm-tool-icon">
<span class="icon"><IconAttachment size="small"/></span>&nbsp;{value.attachments}
</div>

View File

@ -150,6 +150,13 @@
onDestroy(() => {
observer.disconnect()
})
function getCollectionCounter (object: Doc, key: KeyedAttribute): number {
if (client.getHierarchy().isMixin(key.attr.attributeOf)) {
return (client.getHierarchy().as(object, key.attr.attributeOf) as any)[key.key]
}
return (object as any)[key.key] ?? 0
}
</script>
{#if object !== undefined}
@ -202,7 +209,7 @@
{#each collectionKeys as collection}
<div class="mt-14">
{#await getCollectionEditor(collection) then is}
<Component {is} props={{ objectId: object._id, _class: object._class, space: object.space }} />
<Component {is} props={{ objectId: object._id, _class: object._class, space: object.space, [collection.key]: getCollectionCounter(object, collection) }} />
{/await}
</div>
{/each}

View File

@ -15,8 +15,7 @@
<script lang="ts">
import type { Ref } from '@anticrm/core'
import type { Customer, Lead } from '@anticrm/lead'
import { createQuery } from '@anticrm/presentation'
import type { Customer } from '@anticrm/lead'
import task from '@anticrm/task'
import { CircleButton, IconAdd, Label, showPopup } from '@anticrm/ui'
import { Table } from '@anticrm/view-resources'
@ -24,11 +23,8 @@
import CreateLead from './CreateLead.svelte'
export let objectId: Ref<Customer>
let leads: Lead[] = []
const query = createQuery()
$: query.query(lead.class.Lead, { attachedTo: objectId }, result => { leads = result })
export let leads: number | undefined = undefined
$: loadingProps = leads !== undefined ? { length: leads } : undefined
const createLead = (ev: MouseEvent): void =>
showPopup(CreateLead, { candidate: objectId, preserveCandidate: true }, ev.target as HTMLElement)
@ -39,7 +35,7 @@
<div class="title">Leads</div>
<CircleButton icon={IconAdd} size={'small'} selected on:click={createLead} />
</div>
{#if leads.length > 0}
{#if leads !== undefined && leads > 0}
<Table
_class={lead.class.Lead}
config={['', '$lookup.state']}
@ -51,6 +47,7 @@
}
}
query={ { attachedTo: objectId } }
{loadingProps}
/>
{:else}
<div class="flex-col-center mt-5 createapp-container">

View File

@ -14,26 +14,20 @@
-->
<script lang="ts">
import type { Ref, Space, Doc, Class } from '@anticrm/core'
import type { Class, Doc, Ref, Space } from '@anticrm/core'
import core from '@anticrm/core'
import type { Applicant } from '@anticrm/recruit'
import { createQuery } from '@anticrm/presentation'
import { CircleButton, IconAdd, showPopup, Label } from '@anticrm/ui'
import task from '@anticrm/task'
import { CircleButton, IconAdd, Label, showPopup } from '@anticrm/ui'
import { Table } from '@anticrm/view-resources'
import recruit from '../plugin'
import CreateApplication from './CreateApplication.svelte'
import FileDuo from './icons/FileDuo.svelte'
import { Table } from '@anticrm/view-resources'
import task from '@anticrm/task'
import recruit from '../plugin'
export let objectId: Ref<Doc>
export let space: Ref<Space>
export let _class: Ref<Class<Doc>>
let applications: Applicant[] = []
const query = createQuery()
$: query.query(recruit.class.Applicant, { attachedTo: objectId }, result => { applications = result })
export let applications: number
const createApp = (ev: MouseEvent): void =>
showPopup(CreateApplication, { candidate: objectId, preserveCandidate: true }, ev.target as HTMLElement)
@ -44,7 +38,7 @@
<div class="title">Applications</div>
<CircleButton icon={IconAdd} size={'small'} selected on:click={createApp} />
</div>
{#if applications.length > 0}
{#if applications > 0}
<Table
_class={recruit.class.Applicant}
config={['', '$lookup.space.name', '$lookup.state']}
@ -57,6 +51,7 @@
}
}
query={ { attachedTo: objectId } }
loadingProps={ { length: applications } }
/>
{:else}
<div class="flex-col-center mt-5 createapp-container">

View File

@ -38,4 +38,5 @@
}
}
query={ { attachedTo: value._id } }
loadingProps={{ length: value.applications ?? 0 }}
/>

View File

@ -17,9 +17,9 @@
import type { Class, Doc, DocumentQuery, FindOptions, Ref } from '@anticrm/core'
import { SortingOrder } from '@anticrm/core'
import { createQuery, getClient } from '@anticrm/presentation'
import { CheckBox, IconDown, IconUp, Label, Loading, showPopup } from '@anticrm/ui'
import { CheckBox, IconDown, IconUp, Label, Loading, showPopup, Spinner } from '@anticrm/ui'
import { BuildModelKey } from '@anticrm/view'
import { buildModel } from '../utils'
import { buildModel, LoadingProps } from '../utils'
import MoreV from './icons/MoreV.svelte'
import Menu from './Menu.svelte'
@ -28,7 +28,10 @@
export let enableChecking: boolean = false
export let options: FindOptions<Doc> | undefined = undefined
export let baseMenuClass: Ref<Class<Doc>> | undefined = undefined
export let config: (BuildModelKey|string)[]
export let config: (BuildModelKey | string)[]
// If defined, will show a number of dummy items before real data will appear.
export let loadingProps: LoadingProps | undefined = undefined
let sortKey = 'modifiedOn'
let sortOrder = SortingOrder.Descending
@ -38,7 +41,13 @@
const q = createQuery()
async function update(_class: Ref<Class<Doc>>, query: DocumentQuery<Doc>, sortKey: string, sortOrder: SortingOrder, options?: FindOptions<Doc>) {
async function update (
_class: Ref<Class<Doc>>,
query: DocumentQuery<Doc>,
sortKey: string,
sortOrder: SortingOrder,
options?: FindOptions<Doc>
) {
q.query(
_class,
query,
@ -97,6 +106,13 @@
}
checked = checked
}
function getLoadingLength (props: LoadingProps, options?: FindOptions<Doc>): number {
if (options?.limit !== undefined && options?.limit > 0) {
return Math.min(options?.limit, props.length)
}
return props.length
}
</script>
{#await buildModel({ client, _class, keys: config, options })}
@ -158,24 +174,46 @@
</div>
</td>
{/if}
<td
><div class="firstCell">
<td>
<div class="firstCell">
<svelte:component
this={attribute.presenter}
value={getValue(object, attribute.key)}
{...attribute.props}
/>
{...attribute.props}/>
<div class="menuRow" on:click={(ev) => showMenu(ev, object, row)}><MoreV size={'small'} /></div>
</div></td
>
</div>
</td>
{:else}
<td
><svelte:component
<td>
<svelte:component
this={attribute.presenter}
value={getValue(object, attribute.key)}
{...attribute.props}
/></td
>
/>
</td>
{/if}
{/each}
</tr>
{/each}
</tbody>
{:else if loadingProps !== undefined}
<tbody>
{#each Array(getLoadingLength(loadingProps, options)) as i, row}
<tr class="tr-body" class:fixed={row === selectRow}>
{#each model as attribute, cell}
{#if !cell}
{#if enableChecking}
<td>
<div class="checkCell">
<CheckBox
checked={false}
/>
</div>
</td>
{/if}
<td>
<Spinner size="small" />
</td>
{/if}
{/each}
</tr>

View File

@ -30,7 +30,7 @@ import { deleteObject } from './utils'
import MoveView from './components/Move.svelte'
export { default as ContextMenu } from './components/Menu.svelte'
export { buildModel, getActions, getObjectPresenter } from './utils'
export { buildModel, getActions, getObjectPresenter, LoadingProps } from './utils'
export { Table, TableView }
function Delete (object: Doc): void {

View File

@ -22,6 +22,13 @@ import type { Action, ActionTarget, BuildModelOptions } from '@anticrm/view'
import view, { AttributeModel, BuildModelKey } from '@anticrm/view'
import { ErrorPresenter } from '@anticrm/ui'
/**
* Define some properties to be used to show component until data is properly loaded.
*/
export interface LoadingProps {
length: number
}
/**
* @public
*/
@ -37,9 +44,9 @@ export async function getObjectPresenter (client: Client, _class: Ref<Class<Obj>
}
const presenter = await getResource(presenterMixin.presenter)
const key = preserveKey.sortingKey ?? preserveKey.key
const sortingKey = clazz.sortingKey ?
(key.length > 0 ? key + '.' + clazz.sortingKey : clazz.sortingKey)
: key
const sortingKey = clazz.sortingKey !== undefined
? (key.length > 0 ? key + '.' + clazz.sortingKey : clazz.sortingKey)
: key
return {
key: preserveKey.key,
_class,