mirror of
https://github.com/hcengineering/platform.git
synced 2025-05-29 03:21:13 +00:00
parent
aabef475a6
commit
decf27ef0d
@ -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 }}
|
||||
/>
|
||||
|
@ -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>
|
||||
|
@ -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> {value.attachments}
|
||||
</div>
|
||||
|
@ -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}
|
||||
|
@ -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">
|
||||
|
@ -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">
|
||||
|
@ -38,4 +38,5 @@
|
||||
}
|
||||
}
|
||||
query={ { attachedTo: value._id } }
|
||||
loadingProps={{ length: value.applications ?? 0 }}
|
||||
/>
|
||||
|
@ -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>
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user