mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-18 06:13:52 +00:00
Allow collection change display in activity (#1068)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
parent
101c8eb4c3
commit
b1aa6c1132
@ -137,25 +137,9 @@ export const recruitOperation: MigrateOperation = {
|
|||||||
|
|
||||||
// Rename other
|
// Rename other
|
||||||
const categories = await client.find(DOMAIN_TAGS, { _class: tags.class.TagCategory })
|
const categories = await client.find(DOMAIN_TAGS, { _class: tags.class.TagCategory })
|
||||||
let prefix = 'tags:category:Category'
|
const prefix = 'tags:category:Category'
|
||||||
for (const c of categories) {
|
for (const c of categories) {
|
||||||
if (c._id.startsWith(prefix) || c._id === 'tags:category:Other') {
|
if (c._id.startsWith(prefix) || c._id === 'tags:category:Other') {
|
||||||
let newCID = c._id.replace(prefix, recruit.category.Category + '.') as Ref<TagCategory>
|
|
||||||
if (c._id === 'tags:category:Other') {
|
|
||||||
newCID = recruit.category.Other
|
|
||||||
}
|
|
||||||
await client.delete(DOMAIN_TAGS, c._id)
|
|
||||||
await client.create(DOMAIN_TAGS, { ...c, _id: newCID, targetClass: recruit.mixin.Candidate })
|
|
||||||
await client.update(DOMAIN_TAGS, { _class: tags.class.TagElement, category: c._id }, {
|
|
||||||
category: newCID,
|
|
||||||
targetClass: recruit.mixin.Candidate
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
prefix = 'recruit:category:Category'
|
|
||||||
for (const c of categories) {
|
|
||||||
if ((c._id.startsWith(prefix) && !c._id.startsWith(prefix + '.')) || c._id === 'tags:category:Other') {
|
|
||||||
let newCID = c._id.replace(prefix, recruit.category.Category + '.') as Ref<TagCategory>
|
let newCID = c._id.replace(prefix, recruit.category.Category + '.') as Ref<TagCategory>
|
||||||
if (c._id === 'tags:category:Other') {
|
if (c._id === 'tags:category:Other') {
|
||||||
newCID = recruit.category.Other
|
newCID = recruit.category.Other
|
||||||
@ -164,7 +148,7 @@ export const recruitOperation: MigrateOperation = {
|
|||||||
try {
|
try {
|
||||||
await client.create(DOMAIN_TAGS, { ...c, _id: newCID, targetClass: recruit.mixin.Candidate })
|
await client.create(DOMAIN_TAGS, { ...c, _id: newCID, targetClass: recruit.mixin.Candidate })
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
// Ignore
|
// ignore
|
||||||
}
|
}
|
||||||
await client.update(DOMAIN_TAGS, { _class: tags.class.TagElement, category: c._id }, {
|
await client.update(DOMAIN_TAGS, { _class: tags.class.TagElement, category: c._id }, {
|
||||||
category: newCID,
|
category: newCID,
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
"Changed": "changed",
|
"Changed": "changed",
|
||||||
"To": "to",
|
"To": "to",
|
||||||
"Unset": "unset",
|
"Unset": "unset",
|
||||||
"System": "System"
|
"System": "System",
|
||||||
|
"CollectionUpdated": "Update {collection}"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -9,6 +9,7 @@
|
|||||||
"Changed": "изменил(а)",
|
"Changed": "изменил(а)",
|
||||||
"To": "на",
|
"To": "на",
|
||||||
"Unset": "сбросил",
|
"Unset": "сбросил",
|
||||||
"System": "Система"
|
"System": "Система",
|
||||||
|
"CollectionUpdated": "Обновлена {collection}"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,7 +6,6 @@ import core, {
|
|||||||
Client,
|
Client,
|
||||||
Collection,
|
Collection,
|
||||||
Doc,
|
Doc,
|
||||||
DocumentUpdate,
|
|
||||||
Hierarchy,
|
Hierarchy,
|
||||||
Ref,
|
Ref,
|
||||||
SortingOrder,
|
SortingOrder,
|
||||||
@ -32,7 +31,13 @@ export function activityKey (objectClass: Ref<Class<Doc>>, txClass: Ref<Class<Tx
|
|||||||
return objectClass + ':' + txClass
|
return objectClass + ':' + txClass
|
||||||
}
|
}
|
||||||
|
|
||||||
function isEqualOps (op1: DocumentUpdate<Doc>, op2: DocumentUpdate<Doc>): boolean {
|
function isEqualOps (op1: any, op2: any): boolean {
|
||||||
|
if (typeof op1 === 'string' && typeof op2 === 'string') {
|
||||||
|
return op1 === op2
|
||||||
|
}
|
||||||
|
if (typeof op1 !== typeof op2) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
const o1 = Object.keys(op1).sort().join('-')
|
const o1 = Object.keys(op1).sort().join('-')
|
||||||
const o2 = Object.keys(op2).sort().join('-')
|
const o2 = Object.keys(op2).sort().join('-')
|
||||||
return o1 === o2
|
return o1 === o2
|
||||||
@ -47,7 +52,7 @@ export interface DisplayTx {
|
|||||||
tx: TxCUD<Doc>
|
tx: TxCUD<Doc>
|
||||||
|
|
||||||
// A set of collapsed transactions.
|
// A set of collapsed transactions.
|
||||||
txes: Array<TxCUD<Doc>>
|
txes: DisplayTx[]
|
||||||
|
|
||||||
// type check for createTx
|
// type check for createTx
|
||||||
createTx?: TxCreateDoc<Doc>
|
createTx?: TxCreateDoc<Doc>
|
||||||
@ -81,7 +86,7 @@ const combineThreshold = 5 * 60 * 1000
|
|||||||
* Allow to recieve a list of transactions and notify client about it.
|
* Allow to recieve a list of transactions and notify client about it.
|
||||||
*/
|
*/
|
||||||
export interface Activity {
|
export interface Activity {
|
||||||
update: (object: Doc, listener: DisplayTxListener, sort: SortingOrder) => void
|
update: (object: Doc, listener: DisplayTxListener, sort: SortingOrder, editable: Map<Ref<Class<Doc>>, boolean>) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
class ActivityImpl implements Activity {
|
class ActivityImpl implements Activity {
|
||||||
@ -99,8 +104,8 @@ class ActivityImpl implements Activity {
|
|||||||
this.txQuery2 = createQuery()
|
this.txQuery2 = createQuery()
|
||||||
}
|
}
|
||||||
|
|
||||||
private notify (object: Doc, listener: DisplayTxListener, sort: SortingOrder): void {
|
private notify (object: Doc, listener: DisplayTxListener, sort: SortingOrder, editable: Map<Ref<Class<Doc>>, boolean>): void {
|
||||||
this.combineTransactions(object, this.txes1, this.txes2).then(
|
this.combineTransactions(object, this.txes1, this.txes2, editable).then(
|
||||||
(result) => {
|
(result) => {
|
||||||
const sorted = result.sort((a, b) => (a.tx.modifiedOn - b.tx.modifiedOn) * sort)
|
const sorted = result.sort((a, b) => (a.tx.modifiedOn - b.tx.modifiedOn) * sort)
|
||||||
listener(sorted)
|
listener(sorted)
|
||||||
@ -111,7 +116,7 @@ class ActivityImpl implements Activity {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
update (object: Doc, listener: DisplayTxListener, sort: SortingOrder): void {
|
update (object: Doc, listener: DisplayTxListener, sort: SortingOrder, editable: Map<Ref<Class<Doc>>, boolean>): void {
|
||||||
let isAttached = false
|
let isAttached = false
|
||||||
|
|
||||||
isAttached = this.client.getHierarchy().isDerived(object._class, core.class.AttachedDoc)
|
isAttached = this.client.getHierarchy().isDerived(object._class, core.class.AttachedDoc)
|
||||||
@ -128,7 +133,7 @@ class ActivityImpl implements Activity {
|
|||||||
},
|
},
|
||||||
(result) => {
|
(result) => {
|
||||||
this.txes1 = result
|
this.txes1 = result
|
||||||
this.notify(object, listener, sort)
|
this.notify(object, listener, sort, editable)
|
||||||
},
|
},
|
||||||
{ sort: { modifiedOn: SortingOrder.Descending } }
|
{ sort: { modifiedOn: SortingOrder.Descending } }
|
||||||
)
|
)
|
||||||
@ -141,13 +146,13 @@ class ActivityImpl implements Activity {
|
|||||||
},
|
},
|
||||||
(result) => {
|
(result) => {
|
||||||
this.txes2 = result
|
this.txes2 = result
|
||||||
this.notify(object, listener, sort)
|
this.notify(object, listener, sort, editable)
|
||||||
},
|
},
|
||||||
{ sort: { modifiedOn: SortingOrder.Descending } }
|
{ sort: { modifiedOn: SortingOrder.Descending } }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async combineTransactions (object: Doc, txes1: Array<TxCUD<Doc>>, txes2: Array<TxCUD<Doc>>): Promise<DisplayTx[]> {
|
async combineTransactions (object: Doc, txes1: Array<TxCUD<Doc>>, txes2: Array<TxCUD<Doc>>, editable: Map<Ref<Class<Doc>>, boolean>): Promise<DisplayTx[]> {
|
||||||
const hierarchy = this.client.getHierarchy()
|
const hierarchy = this.client.getHierarchy()
|
||||||
|
|
||||||
// We need to sort with with natural order, to build a proper doc values.
|
// We need to sort with with natural order, to build a proper doc values.
|
||||||
@ -163,7 +168,7 @@ class ActivityImpl implements Activity {
|
|||||||
// We do not need collection object updates, in main list of displayed transactions.
|
// We do not need collection object updates, in main list of displayed transactions.
|
||||||
if (this.isDisplayTxRequired(collectionCUD, updateCUD || mixinCUD, ntx, object)) {
|
if (this.isDisplayTxRequired(collectionCUD, updateCUD || mixinCUD, ntx, object)) {
|
||||||
// Combine previous update transaction for same field and if same operation and time treshold is ok
|
// Combine previous update transaction for same field and if same operation and time treshold is ok
|
||||||
results = this.integrateTxWithResults(results, result)
|
results = this.integrateTxWithResults(results, result, editable)
|
||||||
this.updateRemovedState(result, results)
|
this.updateRemovedState(result, results)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -248,7 +253,7 @@ class ActivityImpl implements Activity {
|
|||||||
// Ignore
|
// Ignore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
collectionCUD = true
|
collectionCUD = (cltx.tx._class === core.class.TxUpdateDoc) || (cltx.tx._class === core.class.TxMixin)
|
||||||
}
|
}
|
||||||
let firstTx = parents.get(tx.objectId)
|
let firstTx = parents.get(tx.objectId)
|
||||||
const result: DisplayTx = newDisplayTx(tx, hierarchy)
|
const result: DisplayTx = newDisplayTx(tx, hierarchy)
|
||||||
@ -295,22 +300,21 @@ class ActivityImpl implements Activity {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
integrateTxWithResults (results: DisplayTx[], result: DisplayTx): DisplayTx[] {
|
integrateTxWithResults (results: DisplayTx[], result: DisplayTx, editable: Map<Ref<Class<Doc>>, boolean>): DisplayTx[] {
|
||||||
const curUpdate: any =
|
const curUpdate: any = getCombineOpFromTx(result)
|
||||||
result.tx._class === core.class.TxUpdateDoc
|
|
||||||
? (result.tx as unknown as TxUpdateDoc<Doc>).operations
|
|
||||||
: (result.tx as unknown as TxMixin<Doc, Doc>).attributes
|
|
||||||
|
|
||||||
|
if (curUpdate === undefined || (result.doc !== undefined && editable.has(result.doc._class))) {
|
||||||
|
results.push(result)
|
||||||
|
return results
|
||||||
|
}
|
||||||
const newResult = results.filter((prevTx) => {
|
const newResult = results.filter((prevTx) => {
|
||||||
if (this.isSameKindTx(prevTx, result, result.tx._class)) {
|
const prevUpdate: any = getCombineOpFromTx(prevTx)
|
||||||
const prevUpdate: any =
|
// If same tx or same collection
|
||||||
prevTx.tx._class === core.class.TxUpdateDoc
|
if (this.isSameKindTx(prevTx, result, result.tx._class) || (prevUpdate === curUpdate)) {
|
||||||
? (prevTx.tx as unknown as TxUpdateDoc<Doc>).operations
|
|
||||||
: (prevTx.tx as unknown as TxMixin<Doc, Doc>).attributes
|
|
||||||
if (result.tx.modifiedOn - prevTx.tx.modifiedOn < combineThreshold && isEqualOps(prevUpdate, curUpdate)) {
|
if (result.tx.modifiedOn - prevTx.tx.modifiedOn < combineThreshold && isEqualOps(prevUpdate, curUpdate)) {
|
||||||
// we have same keys,
|
// we have same keys,
|
||||||
// Remember previous transactions
|
// Remember previous transactions
|
||||||
result.txes.push(...prevTx.txes, prevTx.tx)
|
result.txes.push(...prevTx.txes, prevTx)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -331,6 +335,20 @@ class ActivityImpl implements Activity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getCombineOpFromTx (result: DisplayTx): any {
|
||||||
|
let curUpdate: any
|
||||||
|
if (result.tx._class === core.class.TxUpdateDoc) {
|
||||||
|
curUpdate = (result.tx as unknown as TxUpdateDoc<Doc>).operations
|
||||||
|
}
|
||||||
|
if (result.tx._class === core.class.TxMixin) {
|
||||||
|
curUpdate = (result.tx as unknown as TxMixin<Doc, Doc>).attributes
|
||||||
|
}
|
||||||
|
if (result.collectionAttribute !== undefined) {
|
||||||
|
curUpdate = result.collectionAttribute.attributeOf + '.' + result.collectionAttribute.name
|
||||||
|
}
|
||||||
|
return curUpdate
|
||||||
|
}
|
||||||
|
|
||||||
export function newDisplayTx (tx: TxCUD<Doc>, hierarchy: Hierarchy): DisplayTx {
|
export function newDisplayTx (tx: TxCUD<Doc>, hierarchy: Hierarchy): DisplayTx {
|
||||||
const createTx = hierarchy.isDerived(tx._class, core.class.TxCreateDoc) ? (tx as TxCreateDoc<Doc>) : undefined
|
const createTx = hierarchy.isDerived(tx._class, core.class.TxCreateDoc) ? (tx as TxCreateDoc<Doc>) : undefined
|
||||||
return {
|
return {
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import activity, { TxViewlet } from '@anticrm/activity'
|
import activity, { TxViewlet } from '@anticrm/activity'
|
||||||
import chunter from '@anticrm/chunter'
|
import chunter from '@anticrm/chunter'
|
||||||
import { Doc, SortingOrder } from '@anticrm/core'
|
import { Class, Doc, Ref, SortingOrder } from '@anticrm/core'
|
||||||
import { createQuery, getClient } from '@anticrm/presentation'
|
import { createQuery, getClient } from '@anticrm/presentation'
|
||||||
import { Component, Grid, IconActivity, Label, Scroller } from '@anticrm/ui'
|
import { Component, Grid, IconActivity, Label, Scroller } from '@anticrm/ui'
|
||||||
import { ActivityKey, activityKey, DisplayTx, newActivity } from '../activity'
|
import { ActivityKey, activityKey, DisplayTx, newActivity } from '../activity'
|
||||||
@ -33,20 +33,25 @@
|
|||||||
|
|
||||||
const activityQuery = newActivity(client, attrs)
|
const activityQuery = newActivity(client, attrs)
|
||||||
|
|
||||||
|
let viewlets: Map<ActivityKey, TxViewlet>
|
||||||
|
let editable: Map<Ref<Class<Doc>>, boolean> = new Map()
|
||||||
|
|
||||||
|
const descriptors = createQuery()
|
||||||
|
$: descriptors.query(activity.class.TxViewlet, {}, (result) => {
|
||||||
|
viewlets = new Map(result.map((r) => [activityKey(r.objectClass, r.txClass), r]))
|
||||||
|
|
||||||
|
editable = new Map(result.map(it => [it.objectClass, it.editable ?? false]))
|
||||||
|
})
|
||||||
|
|
||||||
$: activityQuery.update(
|
$: activityQuery.update(
|
||||||
object,
|
object,
|
||||||
(result) => {
|
(result) => {
|
||||||
txes = result
|
txes = result
|
||||||
},
|
},
|
||||||
SortingOrder.Descending
|
SortingOrder.Descending,
|
||||||
|
editable
|
||||||
)
|
)
|
||||||
|
|
||||||
let viewlets: Map<ActivityKey, TxViewlet>
|
|
||||||
|
|
||||||
const descriptors = createQuery()
|
|
||||||
$: descriptors.query(activity.class.TxViewlet, {}, (result) => {
|
|
||||||
viewlets = new Map(result.map((r) => [activityKey(r.objectClass, r.txClass), r]))
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if fullSize || transparent}
|
{#if fullSize || transparent}
|
||||||
|
@ -15,15 +15,25 @@
|
|||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { TxViewlet } from '@anticrm/activity'
|
import type { TxViewlet } from '@anticrm/activity'
|
||||||
import activity from '../plugin'
|
|
||||||
import contact, { EmployeeAccount, formatName } from '@anticrm/contact'
|
import contact, { EmployeeAccount, formatName } from '@anticrm/contact'
|
||||||
import core, { AnyAttribute, Doc, getCurrentAccount, Ref } from '@anticrm/core'
|
import core, { AnyAttribute, Doc, getCurrentAccount, Ref } from '@anticrm/core'
|
||||||
import { Asset, getResource } from '@anticrm/platform'
|
import { Asset, getResource } from '@anticrm/platform'
|
||||||
import { getClient } from '@anticrm/presentation'
|
import { getClient } from '@anticrm/presentation'
|
||||||
import { Component, Icon, IconEdit, IconMoreH, Label, Menu, ShowMore, showPopup, TimeSince } from '@anticrm/ui'
|
import {
|
||||||
|
Component,
|
||||||
|
Icon, IconEdit,
|
||||||
|
IconMoreH,
|
||||||
|
Label,
|
||||||
|
Menu,
|
||||||
|
ShowMore,
|
||||||
|
showPopup,
|
||||||
|
TimeSince
|
||||||
|
} from '@anticrm/ui'
|
||||||
import type { AttributeModel } from '@anticrm/view'
|
import type { AttributeModel } from '@anticrm/view'
|
||||||
import { getActions } from '@anticrm/view-resources'
|
import { getActions } from '@anticrm/view-resources'
|
||||||
import { ActivityKey, DisplayTx } from '../activity'
|
import { ActivityKey, DisplayTx } from '../activity'
|
||||||
|
import activity from '../plugin'
|
||||||
|
import TxViewTx from './TxViewTx.svelte'
|
||||||
import { getValue, TxDisplayViewlet, updateViewlet } from './utils'
|
import { getValue, TxDisplayViewlet, updateViewlet } from './utils'
|
||||||
|
|
||||||
export let tx: DisplayTx
|
export let tx: DisplayTx
|
||||||
@ -50,12 +60,16 @@
|
|||||||
|
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
|
|
||||||
|
function getProps (props: any, edit: boolean): any {
|
||||||
|
return { ...props, edit }
|
||||||
|
}
|
||||||
|
|
||||||
$: updateViewlet(client, viewlets, tx).then((result) => {
|
$: updateViewlet(client, viewlets, tx).then((result) => {
|
||||||
if (result.id === tx.tx._id) {
|
if (result.id === tx.tx._id) {
|
||||||
viewlet = result.viewlet
|
viewlet = result.viewlet
|
||||||
model = result.model
|
model = result.model
|
||||||
modelIcon = result.modelIcon
|
modelIcon = result.modelIcon
|
||||||
props = { ...result.props, edit }
|
props = getProps(result.props, edit)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -76,7 +90,7 @@
|
|||||||
icon: IconEdit,
|
icon: IconEdit,
|
||||||
action: () => {
|
action: () => {
|
||||||
edit = true
|
edit = true
|
||||||
props = { ...props, edit }
|
props = getProps(props, edit)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
...actions.map((a) => ({
|
...actions.map((a) => ({
|
||||||
@ -94,7 +108,7 @@
|
|||||||
}
|
}
|
||||||
const onCancelEdit = () => {
|
const onCancelEdit = () => {
|
||||||
edit = false
|
edit = false
|
||||||
props = { ...props, edit }
|
props = getProps(props, edit)
|
||||||
}
|
}
|
||||||
function isMessageType (attr?: AnyAttribute): boolean {
|
function isMessageType (attr?: AnyAttribute): boolean {
|
||||||
return attr?.type._class === core.class.TypeMarkup
|
return attr?.type._class === core.class.TypeMarkup
|
||||||
@ -147,10 +161,7 @@
|
|||||||
<Label label={viewlet.label} params={viewlet.labelParams ?? {}} />
|
<Label label={viewlet.label} params={viewlet.labelParams ?? {}} />
|
||||||
</span>
|
</span>
|
||||||
{#if viewlet.labelComponent}
|
{#if viewlet.labelComponent}
|
||||||
<Component
|
<Component is={viewlet.labelComponent} {props} />
|
||||||
is={viewlet.labelComponent}
|
|
||||||
{props}
|
|
||||||
/>
|
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
@ -160,7 +171,11 @@
|
|||||||
{#if value === null}
|
{#if value === null}
|
||||||
<span class="lower"><Label label={activity.string.Unset} /> <Label label={m.label} /></span>
|
<span class="lower"><Label label={activity.string.Unset} /> <Label label={m.label} /></span>
|
||||||
{:else}
|
{:else}
|
||||||
<span class="lower" class:flex-grow={hasMessageType}><Label label={activity.string.Changed} /> <Label label={m.label} /> <Label label={activity.string.To} /></span>
|
<span class="lower" class:flex-grow={hasMessageType}
|
||||||
|
><Label label={activity.string.Changed} />
|
||||||
|
<Label label={m.label} />
|
||||||
|
<Label label={activity.string.To} /></span
|
||||||
|
>
|
||||||
{#if hasMessageType}
|
{#if hasMessageType}
|
||||||
<div class="time"><TimeSince value={tx.tx.modifiedOn} /></div>
|
<div class="time"><TimeSince value={tx.tx.modifiedOn} /></div>
|
||||||
{/if}
|
{/if}
|
||||||
@ -180,9 +195,15 @@
|
|||||||
{#each model as m}
|
{#each model as m}
|
||||||
{#await getValue(client, m, tx.mixinTx.attributes) then value}
|
{#await getValue(client, m, tx.mixinTx.attributes) then value}
|
||||||
{#if value === null}
|
{#if value === null}
|
||||||
<span><Label label={activity.string.Unset} /> <span class="lower"><Label label={m.label} /></span></span>
|
<span>
|
||||||
|
<Label label={activity.string.Unset} /> <span class="lower"><Label label={m.label} /></span>
|
||||||
|
</span>
|
||||||
{:else}
|
{:else}
|
||||||
<span><Label label={activity.string.Changed} /> <span class="lower"><Label label={m.label} /></span> <Label label={activity.string.To} /></span>
|
<span>
|
||||||
|
<Label label={activity.string.Changed} />
|
||||||
|
<span class="lower"><Label label={m.label} /></span>
|
||||||
|
<Label label={activity.string.To} />
|
||||||
|
</span>
|
||||||
{#if isMessageType(m.attribute)}
|
{#if isMessageType(m.attribute)}
|
||||||
<div class="strong message emphasized">
|
<div class="strong message emphasized">
|
||||||
<svelte:component this={m.presenter} {value} />
|
<svelte:component this={m.presenter} {value} />
|
||||||
@ -196,12 +217,20 @@
|
|||||||
{/await}
|
{/await}
|
||||||
{/each}
|
{/each}
|
||||||
{:else if viewlet && viewlet.display === 'inline' && viewlet.component}
|
{:else if viewlet && viewlet.display === 'inline' && viewlet.component}
|
||||||
|
{#if tx.collectionAttribute !== undefined && tx.txes.length > 0}
|
||||||
|
<ShowMore ignore={edit}>
|
||||||
|
<div class="flex-row-center flex-grow flex-wrap">
|
||||||
|
<TxViewTx {tx} {onCancelEdit} {edit} {viewlet}/>
|
||||||
|
</div>
|
||||||
|
</ShowMore>
|
||||||
|
{:else}
|
||||||
{#if typeof viewlet.component === 'string'}
|
{#if typeof viewlet.component === 'string'}
|
||||||
<Component is={viewlet.component} {props} on:close={onCancelEdit} />
|
<Component is={viewlet.component} {props} on:close={onCancelEdit} />
|
||||||
{:else}
|
{:else}
|
||||||
<svelte:component this={viewlet.component} {...props} on:close={onCancelEdit} />
|
<svelte:component this={viewlet.component} {...props} on:close={onCancelEdit} />
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{#if !hasMessageType}
|
{#if !hasMessageType}
|
||||||
<div class="time"><TimeSince value={tx.tx.modifiedOn} /></div>
|
<div class="time"><TimeSince value={tx.tx.modifiedOn} /></div>
|
||||||
@ -211,11 +240,17 @@
|
|||||||
{#if viewlet && viewlet.component && viewlet.display !== 'inline'}
|
{#if viewlet && viewlet.component && viewlet.display !== 'inline'}
|
||||||
<div class={viewlet.display}>
|
<div class={viewlet.display}>
|
||||||
<ShowMore ignore={viewlet.display !== 'content' || edit}>
|
<ShowMore ignore={viewlet.display !== 'content' || edit}>
|
||||||
|
{#if tx.collectionAttribute !== undefined && tx.txes.length > 0}
|
||||||
|
<div class="flex-row-center flex-grow flex-wrap">
|
||||||
|
<TxViewTx {tx} {onCancelEdit} {edit} {viewlet}/>
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
{#if typeof viewlet.component === 'string'}
|
{#if typeof viewlet.component === 'string'}
|
||||||
<Component is={viewlet.component} {props} on:close={onCancelEdit} />
|
<Component is={viewlet.component} {props} on:close={onCancelEdit} />
|
||||||
{:else}
|
{:else}
|
||||||
<svelte:component this={viewlet.component} {...props} on:close={onCancelEdit} />
|
<svelte:component this={viewlet.component} {...props} on:close={onCancelEdit} />
|
||||||
{/if}
|
{/if}
|
||||||
|
{/if}
|
||||||
</ShowMore>
|
</ShowMore>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
43
plugins/activity-resources/src/components/TxViewTx.svelte
Normal file
43
plugins/activity-resources/src/components/TxViewTx.svelte
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import core, { Class, Doc, Ref } from '@anticrm/core'
|
||||||
|
import { Component, IconAdd, IconDelete } from '@anticrm/ui'
|
||||||
|
import { DisplayTx } from '../activity'
|
||||||
|
import { getDTxProps, TxDisplayViewlet } from './utils'
|
||||||
|
|
||||||
|
export let tx: DisplayTx
|
||||||
|
export let viewlet: TxDisplayViewlet
|
||||||
|
export let edit: boolean
|
||||||
|
export let onCancelEdit: () => void
|
||||||
|
|
||||||
|
function filterTx (dtx: DisplayTx[], _class: Ref<Class<Doc>>): DisplayTx[] {
|
||||||
|
return dtx.filter((it) => it.tx._class === _class)
|
||||||
|
}
|
||||||
|
function getProps (props: any, edit: boolean): any {
|
||||||
|
return { ...props, edit }
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#each filterTx([tx, ...tx.txes], core.class.TxCreateDoc) as ctx, i}
|
||||||
|
{#if i === 0}
|
||||||
|
<div class='mr-2'>
|
||||||
|
<IconAdd size={'small'} />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{#if typeof viewlet?.component === 'string'}
|
||||||
|
<Component is={viewlet?.component} props={getProps(getDTxProps(ctx), edit)} on:close={onCancelEdit} />
|
||||||
|
{:else}
|
||||||
|
<svelte:component this={viewlet?.component} {...getProps(getDTxProps(ctx), edit)} on:close={onCancelEdit} />
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
{#each filterTx([tx, ...tx.txes], core.class.TxRemoveDoc) as ctx, i}
|
||||||
|
{#if i === 0}
|
||||||
|
<div class='mr-2'>
|
||||||
|
<IconDelete size={'small'} />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{#if typeof viewlet?.component === 'string'}
|
||||||
|
<Component is={viewlet?.component} props={getProps(getDTxProps(ctx), edit)} on:close={onCancelEdit} />
|
||||||
|
{:else}
|
||||||
|
<svelte:component this={viewlet?.component} {...getProps(getDTxProps(ctx), edit)} on:close={onCancelEdit} />
|
||||||
|
{/if}
|
||||||
|
{/each}
|
@ -39,12 +39,16 @@ async function createPseudoViewlet (
|
|||||||
display: 'inline',
|
display: 'inline',
|
||||||
icon: docClass.icon ?? activity.icon.Activity,
|
icon: docClass.icon ?? activity.icon.Activity,
|
||||||
label: label,
|
label: label,
|
||||||
labelParams: { _class: trLabel },
|
labelParams: { _class: trLabel, collection: dtx.collectionAttribute?.label !== undefined ? await translate(dtx.collectionAttribute?.label, {}) : '' },
|
||||||
component: presenter.presenter
|
component: presenter.presenter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getDTxProps (dtx: DisplayTx): any {
|
||||||
|
return { tx: dtx.tx, value: dtx.doc, dtx }
|
||||||
|
}
|
||||||
|
|
||||||
export async function updateViewlet (
|
export async function updateViewlet (
|
||||||
client: TxOperations,
|
client: TxOperations,
|
||||||
viewlets: Map<ActivityKey, TxViewlet>,
|
viewlets: Map<ActivityKey, TxViewlet>,
|
||||||
@ -59,7 +63,7 @@ export async function updateViewlet (
|
|||||||
const key = activityKey(dtx.tx.objectClass, dtx.tx._class)
|
const key = activityKey(dtx.tx.objectClass, dtx.tx._class)
|
||||||
let viewlet: TxDisplayViewlet = viewlets.get(key)
|
let viewlet: TxDisplayViewlet = viewlets.get(key)
|
||||||
|
|
||||||
const props = { tx: dtx.tx, value: dtx.doc, dtx }
|
const props = getDTxProps(dtx)
|
||||||
let model: AttributeModel[] = []
|
let model: AttributeModel[] = []
|
||||||
let modelIcon: Asset | undefined
|
let modelIcon: Asset | undefined
|
||||||
|
|
||||||
@ -84,14 +88,15 @@ async function checkInlineViewlets (
|
|||||||
client: TxOperations,
|
client: TxOperations,
|
||||||
model: AttributeModel[]
|
model: AttributeModel[]
|
||||||
): Promise<{ viewlet: TxDisplayViewlet, model: AttributeModel[] }> {
|
): Promise<{ viewlet: TxDisplayViewlet, model: AttributeModel[] }> {
|
||||||
if (dtx.tx._class === core.class.TxCreateDoc) {
|
if (dtx.collectionAttribute !== undefined && dtx.txes.length > 0) {
|
||||||
|
// Check if we have a class presenter we could have a pseudo viewlet based on class presenter.
|
||||||
|
viewlet = await createPseudoViewlet(client, dtx, activity.string.CollectionUpdated)
|
||||||
|
} else if (dtx.tx._class === core.class.TxCreateDoc) {
|
||||||
// Check if we have a class presenter we could have a pseudo viewlet based on class presenter.
|
// Check if we have a class presenter we could have a pseudo viewlet based on class presenter.
|
||||||
viewlet = await createPseudoViewlet(client, dtx, activity.string.DocCreated)
|
viewlet = await createPseudoViewlet(client, dtx, activity.string.DocCreated)
|
||||||
}
|
} else if (dtx.tx._class === core.class.TxRemoveDoc) {
|
||||||
if (dtx.tx._class === core.class.TxRemoveDoc) {
|
|
||||||
viewlet = await createPseudoViewlet(client, dtx, activity.string.DocDeleted)
|
viewlet = await createPseudoViewlet(client, dtx, activity.string.DocDeleted)
|
||||||
}
|
} else if (dtx.tx._class === core.class.TxUpdateDoc) {
|
||||||
if (dtx.tx._class === core.class.TxUpdateDoc) {
|
|
||||||
model = await createUpdateModel(dtx, client, model)
|
model = await createUpdateModel(dtx, client, model)
|
||||||
}
|
}
|
||||||
return { viewlet, model }
|
return { viewlet, model }
|
||||||
|
@ -21,6 +21,7 @@ export default mergeIds(activityId, activity, {
|
|||||||
string: {
|
string: {
|
||||||
DocCreated: '' as IntlString,
|
DocCreated: '' as IntlString,
|
||||||
DocDeleted: '' as IntlString,
|
DocDeleted: '' as IntlString,
|
||||||
|
CollectionUpdated: '' as IntlString,
|
||||||
Changed: '' as IntlString,
|
Changed: '' as IntlString,
|
||||||
To: '' as IntlString,
|
To: '' as IntlString,
|
||||||
Unset: '' as IntlString,
|
Unset: '' as IntlString,
|
||||||
|
Loading…
Reference in New Issue
Block a user